Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>(fnThisType)); } } } if (parent == null) { codingConvention.defineDelegateProxyPrototypeProperties( typeRegistry, newScope, delegateProxyPrototypes, delegateCallingConventions); } return newScope; } /** * Patches a given global scope by removing variables previously declared in * a script and re-traversing a new version of that script. * * @param globalScope The global scope generated by {@code createScope}. * @param scriptRoot The script that is modified. */ void patchGlobalScope(Scope globalScope, Node scriptRoot) { // Preconditions: This is supposed to be called only on (named) SCRIPT nodes // and a global typed scope should have been generated already. Preconditions.checkState(scriptRoot.isScript()); Preconditions.checkNotNull(globalScope); Preconditions.checkState(globalScope.isGlobal()); String scriptName = NodeUtil.getSourceName(scriptRoot); Preconditions.checkNotNull(scriptName); for (Node node : ImmutableList.copyOf(functionAnalysisResults.keySet())) { if (scriptName.equals(NodeUtil.getSourceName(node))) { functionAnalysisResults.remove(node); } } (new FirstOrderFunctionAnalyzer( compiler, functionAnalysisResults)).process(null, scriptRoot); // TODO(bashir): Variable declaration is not the only side effect of last // global scope generation but here we only wipe that part off! // Remove all variables that were previously declared in this scripts. // First find all vars to remove then remove them because of iterator! Iterator<Var> varIter = globalScope.getVars(); List<Var> varsToRemove = Lists.newArrayList(); while (varIter.hasNext()) { Var oldVar = varIter.next(); if (scriptName.equals(oldVar.getInputName())) { varsToRemove.add(oldVar); } } for (Var var : varsToRemove) { globalScope.undeclare(var); globalScope.getTypeOfThis().removeProperty(var.getName()); } // Now re-traverse the given script. GlobalScopeBuilder scopeBuilder = new GlobalScopeBuilder(globalScope); NodeTraversal.traverse(compiler, scriptRoot, scopeBuilder); } /** * Create the outermost

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>, null, false); } private static class DiscoverEnumsAndTypedefs extends AbstractShallowStatementCallback { private final JSTypeRegistry registry; DiscoverEnumsAndTypedefs(JSTypeRegistry registry) { this.registry = registry; } @Override public void visit(NodeTraversal t, Node node, Node parent) { Node nameNode = null; switch (node.getType()) { case Token.VAR: for (Node child = node.getFirstChild(); child != null; child = child.getNext()) { identifyNameNode( child, child.getFirstChild(), NodeUtil.getBestJSDocInfo(child)); } break; case Token.EXPR_RESULT: Node firstChild = node.getFirstChild(); if (firstChild.isAssign()) { identifyNameNode( firstChild.getFirstChild(), firstChild.getLastChild(), firstChild.getJSDocInfo()); } else { identifyNameNode( firstChild, null, firstChild.getJSDocInfo()); } break; } } private void identifyNameNode( Node nameNode, Node valueNode, JSDocInfo info) { if (nameNode.isQualifiedName()) { if (info != null) { if (info.hasEnumParameterType()) { registry.identifyNonNullableName(nameNode.getQualifiedName()); } else if (info.hasTypedefType()) { registry.identifyNonNullableName(nameNode.getQualifiedName()); } } } } } private JSType getNativeType(JSTypeNative nativeType) { return typeRegistry.getNativeType(nativeType); } private abstract class AbstractScopeBuilder implements NodeTraversal.Callback { /** * The scope that we're builidng. /** * The InputId of the current node. */ private InputId inputId; private AbstractScopeBuilder(Scope scope) { this.scope = scope; } void setDeferredType(Node node, JSType type) { deferredSetTypes.add(new DeferredSetType(node, type)); } void resolveTypes() { // Resolve types and attach them to nodes. for (DeferredSetType deferred : deferredSetTypes) { deferred.resolve(scope); } //

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> Resolve types and attach them to scope slots. Iterator<Var> vars = scope.getVars(); while (vars.hasNext()) { vars.next().resolveType(typeParsingErrorReporter); } // Tell the type registry that any remaining types // are unknown. typeRegistry.resolveTypesInScope(scope); } @Override public final boolean shouldTraverse(NodeTraversal t, Node n, Node parent) { inputId = t.getInputId(); if (n.isFunction() || n.isScript()) { Preconditions.checkNotNull(inputId); sourceName = NodeUtil.getSourceName(n); } // We do want to traverse the name of a named function, but we don't // want to traverse the arguments or body. boolean descend = parent == null || !parent.isFunction() || n == parent.getFirstChild() || parent == scope.getRootNode(); if (descend) { // Handle hoisted functions on pre-order traversal, so that they // get hit before other things in the scope. if (NodeUtil.isStatementParent(n)) { for (Node child = n.getFirstChild(); child != null; child = child.getNext()) { if (NodeUtil.isHoistedFunctionDeclaration(child)) { defineFunctionLiteral(child, n); } } } } return descend; } @Override public void visit(NodeTraversal t, Node n, Node parent) { inputId = t.getInputId(); attachLiteralTypes(t, n); switch (n.getType()) { case Token.CALL: checkForClassDefiningCalls(t, n, parent); checkForCallingConventionDefiningCalls(n, delegateCallingConventions); break; case Token.FUNCTION: if (t.getInput() == null || !t.getInput().isExtern()) { nonExternFunctions.add(n); } // Hoisted functions are handled during pre-traversal. if (!NodeUtil.isHoistedFunctionDeclaration(n)) { defineFunctionLiteral(n, parent); } break; case Token.ASSIGN: // Handle initialization of properties. Node firstChild = n.getFirstChild(); if (firstChild.isGetProp() && firstChild.

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), Var lendsVar = scope.getVar(lendsName); if (lendsVar == null) { compiler.report( JSError.make(sourceName, objectLit, UNKNOWN_LENDS, lendsName)); } else { type = lendsVar.getType(); if (type == null) { type = typeRegistry.getNativeType(UNKNOWN_TYPE); } if (!type.isSubtype(typeRegistry.getNativeType(OBJECT_TYPE))) { compiler.report( JSError.make(sourceName, objectLit, LENDS_ON_NON_OBJECT, lendsName, type.toString())); type = null; } else { objectLit.setJSType(type); } } } info = NodeUtil.getBestJSDocInfo(objectLit); Node lValue = NodeUtil.getBestLValue(objectLit); String lValueName = NodeUtil.getBestLValueName(lValue); boolean createdEnumType = false; if (info != null && info.hasEnumParameterType()) { type = createEnumTypeFromNodes(objectLit, lValueName, info, lValue); createdEnumType = true; } if (type == null) { type = typeRegistry.createAnonymousObjectType(); } setDeferredType(objectLit, type); // If this is an enum, the properties were already taken care of above. processObjectLitProperties( objectLit, ObjectType.cast(objectLit.getJSType()), !createdEnumType); } /** * Process an object literal and all the types on it. * @param objLit The OBJECTLIT node. * @param objLitType The type of the OBJECTLIT node. This might be a named * type, because of the lends annotation. * @param declareOnOwner If true, declare properties on the objLitType as * well. If false, the caller should take crae of this. */ void processObjectLitProperties( Node objLit, ObjectType objLitType, boolean declareOnOwner) { for (Node keyNode = objLit.getFirstChild(); keyNode != null; keyNode = keyNode

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>.getNext()) { Node value = keyNode.getFirstChild(); String memberName = NodeUtil.getObjectLitKeyName(keyNode); JSDocInfo info = keyNode.getJSDocInfo(); JSType valueType = getDeclaredType(keyNode.getSourceFileName(), info, keyNode, value); JSType keyType = objLitType.isEnumType() ? objLitType.toMaybeEnumType().getElementsType() : NodeUtil.getObjectLitKeyTypeFromValueType(keyNode, valueType); // Try to declare this property in the current scope if it // has an authoritative name. String qualifiedName = NodeUtil.getBestLValueName(keyNode); if (qualifiedName != null) { boolean inferred = keyType == null; defineSlot(keyNode, objLit, qualifiedName, keyType, inferred); } else if (keyType != null) { setDeferredType(keyNode, keyType); } if (keyType != null && objLitType != null && declareOnOwner) { // Declare this property on its object literal. boolean isExtern = keyNode.isFromExterns(); objLitType.defineDeclaredProperty(memberName, keyType, keyNode); } } } /** * Returns the type specified in a JSDoc annotation near a GETPROP or NAME. * * Extracts type information from either the {@code @type} tag or from * the {@code @return} and {@code @param} tags. */ private JSType getDeclaredTypeInAnnotation(String sourceName, Node node, JSDocInfo info) { JSType jsType = null; Node objNode = node.isGetProp() ? node.getFirstChild() : NodeUtil.isObjectLitKey(node, node.getParent()) ? node.getParent() : null; if (info != null) { if (info.hasType()) { jsType = info.getType().evaluate(scope, typeRegistry); } else if (FunctionTypeBuilder.isFunctionTypeDeclaration(info)) { String fnName = node.getQualifiedName(); jsType = createFunctionTypeFromNodes( null, fnName, info, node); } } return jsType; } /** * Asserts that it

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>Type delegateProxy = typeRegistry.createConstructorType( delegateBaseObject.getReferenceName() + DELEGATE_PROXY_SUFFIX, null, null, null); delegateProxy.setPrototypeBasedOn(delegateBaseObject); codingConvention.applyDelegateRelationship( delegateSuperObject, delegateBaseObject, delegatorObject, delegateProxy, findDelegate); delegateProxyPrototypes.add(delegateProxy.getPrototype()); } } } /** * Declare the symbol for a qualified name in the global scope. * * @param info The doc info for this property. * @param n A top-level GETPROP node (it should not be contained inside * another GETPROP). * @param parent The parent of {@code n}. * @param rhsValue The node that {@code n} is being initialized to, * or {@code null} if this is a stub declaration. */ void maybeDeclareQualifiedName(NodeTraversal t, JSDocInfo info, Node n, Node parent, Node rhsValue) { Node ownerNode = n.getFirstChild(); String ownerName = ownerNode.getQualifiedName(); String qName = n.getQualifiedName(); String propName = n.getLastChild().getString(); Preconditions.checkArgument(qName != null && ownerName != null); // Precedence of type information on GETPROPs: // 1) @type annnotation / @enum annotation // 2) ASSIGN to FUNCTION literal // 3) @param/@return annotation (with no function literal) // 4) ASSIGN to something marked @const // 5) ASSIGN to anything else // // 1, 3, and 4 are declarations, 5 is inferred, and 2 is a declaration iff // the function has jsdoc or has not been declared before. // // FUNCTION literals are special because TypedScopeCreator is very smart // about getting as much type information as possible for them. // Determining type for #1 + #2 + #3 + #4 JSType valueType = getDeclaredType(t.getSourceName(), info, n, rhsValue); if (valueType == null && rhsValue != null) { // Determining type for #5 valueType = rhsValue.getJSType(); } // Function prototypes are special

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>. // It's a common JS idiom to do: // F.prototype = { ... }; // So if F does not have an explicitly declared super type, // allow F.prototype to be redefined arbitrarily. if ("prototype".equals(propName)) { Var qVar = scope.getVar(qName); if (qVar != null) { // If the programmer has declared that F inherits from Super, // and they assign F.prototype to an object literal, // then they are responsible for making sure that the object literal's // implicit prototype is set up appropriately. We just obey // the @extends tag. ObjectType qVarType = ObjectType.cast(qVar.getType()); if (qVarType != null && rhsValue != null && rhsValue.isObjectLit()) { typeRegistry.resetImplicitPrototype( rhsValue.getJSType(), qVarType.getImplicitPrototype()); } else if (!qVar.isTypeInferred()) { // If the programmer has declared that F inherits from Super, // and they assign F.prototype to some arbitrary expression, // there's not much we can do. We just ignore the expression, // and hope they've annotated their code in a way to tell us // what props are going to be on that prototype. return; } if (qVar.getScope() == scope) { scope.undeclare(qVar); } } } if (valueType == null) { if (parent.isExprResult()) { stubDeclarations.add(new StubDeclaration( n, t.getInput() != null && t.getInput().isExtern(), ownerName)); } return; } boolean inferred = isQualifiedNameInferred( qName, n, info, rhsValue, valueType); if (!inferred) { ObjectType ownerType = getObjectSlot(ownerName); if (ownerType != null) { // Only declare this as an official property if it has not been // declared yet. boolean isExtern = t.getInput() != null && t.getInput().isExtern(); if ((!ownerType.hasOwnProperty(propName) || ownerType.isPropertyTypeInferred(propName)) && ((isExtern && !ownerType.isNativeObjectType()) ||

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> t.getScope().getVar(name); if (isConstant(var)) { if (initializedConstants.contains(var)) { reportError(t, n, name); } else { initializedConstants.add(var); } } } break; case Token.ASSIGN: case Token.ASSIGN_BITOR: case Token.ASSIGN_BITXOR: case Token.ASSIGN_BITAND: case Token.ASSIGN_LSH: case Token.ASSIGN_RSH: case Token.ASSIGN_URSH: case Token.ASSIGN_ADD: case Token.ASSIGN_SUB: case Token.ASSIGN_MUL: case Token.ASSIGN_DIV: case Token.ASSIGN_MOD: { Node lhs = n.getFirstChild(); if (lhs.isName()) { String name = lhs.getString(); Scope.Var var = t.getScope().getVar(name); if (isConstant(var)) { if (initializedConstants.contains(var)) { reportError(t, n, name); } else { initializedConstants.add(var); } } } break; } case Token.INC: case Token.DEC: { Node lhs = n.getFirstChild(); if (lhs.isName()) { String name = lhs.getString(); Scope.Var var = t.getScope().getVar(name); if (isConstant(var)) { reportError(t, n, name); } } break; } } } /** * Gets whether a variable is a constant initialized to a literal value at * the point where it is declared. */ private boolean isConstant(Scope.Var var) { return var != null && var.isConst(); } /** * Reports a reassigned constant error. */ void reportError(NodeTraversal t, Node n, String name) { compiler.report(t.makeError(n, CONST_REASSIGNED_VALUE_ERROR, name)); } }

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> else break; } } } else if (pt != Token.EXPR_RESULT && pt != Token.BLOCK) { if (pt == Token.FOR && parent.getChildCount() == 4 && (n == parent.getFirstChild() || n == parent.getFirstChild().getNext().getNext())) { // Fall through and look for warnings for the 1st and 3rd child // of a for. } else { return; // it might be ok to not have a side-effect } } boolean isSimpleOp = NodeUtil.isSimpleOperatorType(n.getType()); if (isSimpleOp || !NodeUtil.mayHaveSideEffects(n, t.getCompiler())) { if (n.isQualifiedName() && n.getJSDocInfo() != null) { // This no-op statement was there so that JSDoc information could // be attached to the name. This check should not complain about it. return; } else if (n.isExprResult()) { // we already reported the problem when we visited the child. return; } String msg = "This code lacks side-effects. Is there a bug?"; if (n.isString()) { msg = "Is there a missing '+' on the previous line?"; } else if (isSimpleOp) { msg = "The result of the '" + Token.name(n.getType()).toLowerCase() + "' operator is not being used."; } t.getCompiler().report( t.makeError(n, level, USELESS_CODE_ERROR, msg)); // TODO(johnlenz): determine if it is necessary to // try to protect side-effect free statements as well. if (!NodeUtil.isStatement(n)) { problemNodes.add(n); } } } /** * Protect side-effect free nodes by making them parameters * to a extern function call. This call will be removed * after all the optimizations passes have run. */ private void protectSideEffects() { if (!problemNodes.isEmpty()) { addExtern(); for (Node n : problemNodes) { Node name = IR.name(PROTECTOR_FN).srcref(n); name.putBooleanProp(

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> LinkedDirectedGraph<N, E>(true, false); } public static <N, E> LinkedDirectedGraph<N, E> createWithEdgeAnnotations() { return new LinkedDirectedGraph<N, E>(false, true); } public static <N, E> LinkedDirectedGraph<N, E> create() { return new LinkedDirectedGraph<N, E>(true, true); } private final boolean useNodeAnnotations; private final boolean useEdgeAnnotations; protected LinkedDirectedGraph( boolean useNodeAnnotations, boolean useEdgeAnnotations) { this.useNodeAnnotations = useNodeAnnotations; this.useEdgeAnnotations = useEdgeAnnotations; } @Override public void connect(N srcValue, E edgeValue, N destValue) { LinkedDirectedGraphNode<N, E> src = getNodeOrFail(srcValue); LinkedDirectedGraphNode<N, E> dest = getNodeOrFail(destValue); LinkedDirectedGraphEdge<N, E> edge = useEdgeAnnotations ? new AnnotatedLinkedDirectedGraphEdge<N, E>(src, edgeValue, dest) : new LinkedDirectedGraphEdge<N, E>(src, edgeValue, dest); src.getOutEdges().add(edge); dest.getInEdges().add(edge); } @Override public void disconnect(N n1, N n2) { disconnectInDirection(n1, n2); disconnectInDirection(n2, n1); } @Override public void disconnectInDirection(N srcValue, N destValue) { LinkedDirectedGraphNode<N, E> src = getNodeOrFail(srcValue); LinkedDirectedGraphNode<N, E> dest = getNodeOrFail(destValue); for (DiGraphEdge<?, E> edge : getDirectedGraphEdges(srcValue, destValue)) { src.getOutEdges().remove(edge); dest.getInEdges().remove(edge); } } @Override public Iterable<DiGraphNode<N, E>> getDirectedGraphNodes() { return Collections.<DiGraphNode<N, E>>unmodifiableCollection( nodes.values()); } @Override public DiGraphNode<N, E> getDirectedGraphNode(N nodeValue) {

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>); for (DiGraphEdge<N, E> outEdge : dNode1.getOutEdges()) { if (outEdge.getDestination() == dNode2) { return outEdge; } } for (DiGraphEdge<N, E> outEdge : dNode2.getOutEdges()) { if (outEdge.getDestination() == dNode1) { return outEdge; } } return null; } @Override public GraphNode<N, E> createNode(N value) { return createDirectedGraphNode(value); } @Override public List<DiGraphEdge<N, E>> getDirectedGraphEdges(N n1, N n2) { DiGraphNode<N, E> dNode1 = getNodeOrFail(n1); DiGraphNode<N, E> dNode2 = getNodeOrFail(n2); List<DiGraphEdge<N, E>> edges = Lists.newArrayList(); for (DiGraphEdge<N, E> outEdge : dNode1.getOutEdges()) { if (outEdge.getDestination() == dNode2) { edges.add(outEdge); } } return edges; } @Override public boolean isConnectedInDirection(N n1, N n2) { return isConnectedInDirection(n1, Predicates.<E>alwaysTrue(), n2); } @Override public boolean isConnectedInDirection(N n1, E edgeValue, N n2) { return isConnectedInDirection(n1, Predicates.equalTo(edgeValue), n2); } private boolean isConnectedInDirection(N n1, Predicate<E> edgeMatcher, N n2) { // Verify the nodes. DiGraphNode<N, E> dNode1 = getNodeOrFail(n1); DiGraphNode<N, E> dNode2 = getNodeOrFail(n2); for (DiGraphEdge<N, E> outEdge : dNode1.getOutEdges()) { if (outEdge.getDestination() == dNode2 && edgeMatcher.apply(outEdge.getValue())) { return true; } } return false; } @Override public List<DiGraphNode<N, E>>

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> getDirectedPredNodes(N nodeValue) { return getDirectedPredNodes(nodes.get(nodeValue)); } @Override public List<DiGraphNode<N, E>> getDirectedSuccNodes(N nodeValue) { return getDirectedSuccNodes(nodes.get(nodeValue)); } @Override public List<DiGraphNode<N, E>> getDirectedPredNodes( DiGraphNode<N, E> dNode) { if (dNode == null) { throw new IllegalArgumentException(dNode + " is null"); } List<DiGraphNode<N, E>> nodeList = Lists.newArrayList(); for (DiGraphEdge<N, E> edge : dNode.getInEdges()) { nodeList.add(edge.getSource()); } return nodeList; } @Override public List<DiGraphNode<N, E>> getDirectedSuccNodes( DiGraphNode<N, E> dNode) { if (dNode == null) { throw new IllegalArgumentException(dNode + " is null"); } List<DiGraphNode<N, E>> nodeList = Lists.newArrayList(); for (DiGraphEdge<N, E> edge : dNode.getOutEdges()) { nodeList.add(edge.getDestination()); } return nodeList; } @Override public List<GraphvizEdge> getGraphvizEdges() { List<GraphvizEdge> edgeList = Lists.newArrayList(); for (LinkedDirectedGraphNode<N, E> node : nodes.values()) { for (DiGraphEdge<N, E> edge : node.getOutEdges()) { edgeList.add((LinkedDirectedGraphEdge<N, E>) edge); } } return edgeList; } @Override public List<GraphvizNode> getGraphvizNodes() { List<GraphvizNode> nodeList = Lists.newArrayListWithCapacity(nodes.size()); for (LinkedDirectedGraphNode<N, E> node : nodes.values()) { nodeList.add(node); } return nodeList; } @Override public String getName() { return "LinkedGraph"; } @Override public boolean isDirected() { return

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> true; } @Override public Collection<GraphNode<N, E>> getNodes() { return Collections.<GraphNode<N, E>>unmodifiableCollection(nodes.values()); } @Override public List<GraphNode<N, E>> getNeighborNodes(N value) { DiGraphNode<N, E> node = getDirectedGraphNode(value); return getNeighborNodes(node); } public List<GraphNode<N, E>> getNeighborNodes(DiGraphNode<N, E> node) { List<GraphNode<N, E>> result = Lists.newArrayList(); for (Iterator<GraphNode<N, E>> i = ((LinkedDirectedGraphNode<N, E>) node).neighborIterator();i.hasNext();) { result.add(i.next()); } return result; } @Override public Iterator<GraphNode<N, E>> getNeighborNodesIterator(N value) { LinkedDirectedGraphNode<N, E> node = nodes.get(value); Preconditions.checkNotNull(node); return node.neighborIterator(); } @Override public List<GraphEdge<N, E>> getEdges() { List<GraphEdge<N, E>> result = Lists.newArrayList(); for (DiGraphNode<N, E> node : nodes.values()) { for (DiGraphEdge<N, E> edge : node.getOutEdges()) { result.add(edge); } } return Collections.unmodifiableList(result); } @Override public int getNodeDegree(N value) { DiGraphNode<N, E> node = getNodeOrFail(value); return node.getInEdges().size() + node.getOutEdges().size(); } /** * A directed graph node that stores outgoing edges and incoming edges as an * list within the node itself. */ static class LinkedDirectedGraphNode<N, E> implements DiGraphNode<N, E>, GraphvizNode { List<DiGraphEdge<N, E>> inEdgeList = Lists.newArrayList(); List<DiGraphEdge<N, E>> outEdgeList = Lists.newArrayList(); protected final N value; /** * Constructor * * @param nodeValue Node's value. */

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> { return createConfig(isIdeMode, languageMode, acceptConstKeyword, null); } public static Config createConfig(boolean isIdeMode, LanguageMode languageMode, boolean acceptConstKeyword, Set<String> extraAnnotationNames) { initResourceConfig(); Set<String> effectiveAnnotationNames; if (extraAnnotationNames == null) { effectiveAnnotationNames = annotationNames; } else { effectiveAnnotationNames = new HashSet<String>(annotationNames); effectiveAnnotationNames.addAll(extraAnnotationNames); } return new Config(effectiveAnnotationNames, suppressionNames, isIdeMode, languageMode, acceptConstKeyword); } private static synchronized void initResourceConfig() { if (annotationNames != null) { return; } ResourceBundle config = ResourceBundle.getBundle(configResource); annotationNames = extractList(config.getString("jsdoc.annotations")); suppressionNames = extractList(config.getString("jsdoc.suppressions")); } private static Set<String> extractList(String configProp) { String[] names = configProp.split(","); Set<String> trimmedNames = Sets.newHashSet(); for (String name : names) { trimmedNames.add(name.trim()); } return ImmutableSet.copyOf(trimmedNames); } /** * Parses the JavaScript text given by a reader. * * @param sourceString Source code from the file. * @param errorReporter An error. * @param logger A logger. * @return The AST of the given text. * @throws IOException */ public static Node parse(StaticSourceFile sourceFile, String sourceString, Config config, ErrorReporter errorReporter, Logger logger) throws IOException { Context cx = Context.enter(); cx.setErrorReporter(errorReporter); cx.setLanguageVersion(Context.VERSION_1_5); CompilerEnvirons compilerEnv = new CompilerEnvirons(); compilerEnv.initFromContext(cx); compilerEnv.setRecordingComments(true); compilerEnv.setRecordingLocalJsDocComments(true); // ES5 specifically allows trailing commas compilerEnv.setWarnTrailingComma( config.languageMode == LanguageMode.ECMASCRIPT3); // Do our own identifier check for ECMASCRIPT 5

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>(instance, implementedInterface, report(JSError.make(sourceName, n, INTERFACE_METHOD_NOT_IMPLEMENTED, prop, implementedInterface.toString(), instance.toString()))); } else { JSType found = instance.getPropertyType(prop); JSType required = implementedInterface.getImplicitPrototype().getPropertyType(prop); found = found.restrictByNotNullOrUndefined(); required = required.restrictByNotNullOrUndefined(); if (!found.canAssignTo(required)) { // Implemented, but not correctly typed FunctionType constructor = implementedInterface.toObjectType().getConstructor(); registerMismatch(found, required, report(t.makeError(n, HIDDEN_INTERFACE_PROPERTY_MISMATCH, prop, constructor.getTopMostDefiningType(prop).toString(), required.toString(), found.toString()))); } } } /** * Report a type mismatch */ private void mismatch(NodeTraversal t, Node n, String msg, JSType found, JSType required) { mismatch(t.getSourceName(), n, msg, found, required); } private void mismatch(NodeTraversal t, Node n, String msg, JSType found, JSTypeNative required) { mismatch(t, n, msg, found, getNativeType(required)); } private void mismatch(String sourceName, Node n, String msg, JSType found, JSType required) { registerMismatch(found, required, report( JSError.make(sourceName, n, TYPE_MISMATCH_WARNING, formatFoundRequired(msg, found, required)))); } private void registerMismatch(JSType found, JSType required, JSError error) { // Don't register a mismatch for differences in null or undefined or if the // code didn't downcast. found = found.restrictByNotNullOrUndefined(); required = required.restrictByNotNullOrUndefined(); if (found.canAssignTo(required) || required.canAssignTo(found)) { return; } mismatches.add(new TypeMismatch(found, required, error)); if (found.isFunctionType() && required.isFunctionType()) { FunctionType fnTypeA = found.toMaybeFunctionType(); FunctionType fnTypeB = required.toMaybeFunctionType(); Iterator<Node>

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> List<Name> allDefines = Lists.newArrayList(); for (Name name : namespace.getNameIndex().values()) { Ref decl = name.getDeclaration(); if (name.docInfo != null && name.docInfo.isDefine()) { // Process defines should not depend on check types being enabled, // so we look for the JSDoc instead of the inferred type. if (isValidDefineType(name.docInfo.getType())) { allDefines.add(name); } else { JSError error = JSError.make( decl.getSourceName(), decl.node, INVALID_DEFINE_TYPE_ERROR); compiler.report(error); } } else { for (Ref ref : name.getRefs()) { if (ref == decl) { // Declarations were handled above. continue; } Node n = ref.node; Node parent = ref.node.getParent(); JSDocInfo info = n.getJSDocInfo(); if (info == null && parent.isVar() && parent.hasOneChild()) { info = parent.getJSDocInfo(); } if (info != null && info.isDefine()) { allDefines.add(name); break; } } } } CollectDefines pass = new CollectDefines(compiler, allDefines); NodeTraversal.traverse(compiler, root, pass); return pass.getAllDefines(); } /** * Finds all assignments to @defines, and figures out the last value of * the @define. */ private static final class CollectDefines implements Callback { private final AbstractCompiler compiler; private final Map<String, DefineInfo> assignableDefines; private final Map<String, DefineInfo> allDefines; private final Map<Node, RefInfo> allRefInfo; // A hack that allows us to remove ASSIGN/VAR statements when // we're currently visiting one of the children of the assign. private Node lvalueToRemoveLater = null; // A stack tied to the node traversal, to keep track of whether // we're in a conditional block. If 1 is at the top, assignment to // a define is allowed. Otherwise, it's not allowed. private final Deque<Integer> assignAllowed; CollectDefines(AbstractCompiler compiler, List<

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> are not. But this would be overkill, expecially because // the intended use of defines is with config_files, where // all the defines are at the top of the bundle. for (DefineInfo info : assignableDefines.values()) { setDefineInfoNotAssignable(info, t); } assignableDefines.clear(); } } updateAssignAllowedStack(n, false); } /** * Determines whether assignment to a define should be allowed * in the subtree of the given node, and if not, records that fact. * * @param n The node whose subtree we're about to enter or exit. * @param entering True if we're entering the subtree, false otherwise. */ private void updateAssignAllowedStack(Node n, boolean entering) { switch (n.getType()) { case Token.CASE: case Token.FOR: case Token.FUNCTION: case Token.HOOK: case Token.IF: case Token.SWITCH: case Token.WHILE: if (entering) { assignAllowed.push(0); } else { assignAllowed.remove(); } break; } } /** * Determines whether assignment to a define should be allowed * at the current point of the traversal. */ private boolean isAssignAllowed() { return assignAllowed.element() == 1; } /** * Tracks the given define. * * @param t The current traversal, for context. * @param name The full name for this define. * @param value The value assigned to the define. * @param valueParent The parent node of value. * @return Whether we should remove this assignment from the parse tree. */ private boolean processDefineAssignment(NodeTraversal t, String name, Node value, Node valueParent) { if (value == null || !NodeUtil.isValidDefineValue(value, allDefines.keySet())) { compiler.report( t.makeError(value, INVALID_DEFINE_INIT_ERROR, name)); } else if (!isAssignAllowed()) { compiler.report( t.makeError(valueParent, NON_GLOBAL_DEFINE_INIT_ERROR, name)); } else { DefineInfo info = allDefines.get(name); if (info == null)

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> computation for an edge case. This seems to be // a "good enough" approximation. // conditionOutcomes is cached from previous iterations // of the loop. if (conditionOutcomes == null) { conditionOutcomes = condition.isAnd() ? traverseAnd(condition, output.createChildFlowScope()) : traverseOr(condition, output.createChildFlowScope()); } newScope = reverseInterpreter.getPreciserScopeKnowingConditionOutcome( condition, conditionOutcomes.getOutcomeFlowScope( condition.getType(), branch == Branch.ON_TRUE), branch == Branch.ON_TRUE); } else { // conditionFlowScope is cached from previous iterations // of the loop. if (conditionFlowScope == null) { conditionFlowScope = traverse(condition, output.createChildFlowScope()); } newScope = reverseInterpreter.getPreciserScopeKnowingConditionOutcome( condition, conditionFlowScope, branch == Branch.ON_TRUE); } } break; } result.add(newScope.optimize()); } return result; } private FlowScope traverse(Node n, FlowScope scope) { switch (n.getType()) { case Token.ASSIGN: scope = traverseAssign(n, scope); break; case Token.NAME: scope = traverseName(n, scope); break; case Token.GETPROP: scope = traverseGetProp(n, scope); break; case Token.AND: scope = traverseAnd(n, scope).getJoinedFlowScope() .createChildFlowScope(); break; case Token.OR: scope = traverseOr(n, scope).getJoinedFlowScope() .createChildFlowScope(); break; case Token.HOOK: scope = traverseHook(n, scope); break; case Token.OBJECTLIT: scope = traverseObjectLiteral(n, scope); break; case Token.CALL: scope = traverseCall(n, scope); break; case Token.NEW: scope = traverseNew(n, scope); break; case Token.ASSIGN_ADD: case Token.ADD: scope = traverseAdd(n, scope); break; case Token.POS: case Token.NEG: scope

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> while (it.hasNext()) { scope = scopeCreator.createScope(it.next(), scope); scopes.push(scope); } scopeRoots.clear(); return scope; } /** Gets the control flow graph for the current JS scope. */ public ControlFlowGraph<Node> getControlFlowGraph() { if (cfgs.peek() == null) { ControlFlowAnalysis cfa = new ControlFlowAnalysis(compiler, false, true); cfa.process(null, getScopeRoot()); cfgs.pop(); cfgs.push(cfa.getCfg()); } return cfgs.peek(); } /** Returns the current scope's root. */ public Node getScopeRoot() { if (scopeRoots.isEmpty()) { return scopes.peek().getRootNode(); } else { return scopeRoots.peek(); } } /** * Determines whether the traversal is currently in the global scope. */ boolean inGlobalScope() { return getScopeDepth() <= 1; } int getScopeDepth() { return scopes.size() + scopeRoots.size(); } public boolean hasScope() { return !(scopes.isEmpty() && scopeRoots.isEmpty()); } /** Reports a diagnostic (error or warning) */ public void report(Node n, DiagnosticType diagnosticType, String... arguments) { JSError error = JSError.make(getSourceName(), n, diagnosticType, arguments); compiler.report(error); } private static String getSourceName(Node n) { String name = n.getSourceFileName(); return name == null ? "" : name; } InputId getInputId() { return inputId; } /** * Creates a JSError during NodeTraversal. * * @param n Determines the line and char position within the source file name * @param type The DiagnosticType * @param arguments Arguments to be incorporated into the message */ public JSError makeError(Node n, CheckLevel level, DiagnosticType type, String... arguments) { return JSError.make(getSourceName(), n, level, type, arguments); } /** * Creates a JSError during NodeTraversal. * * @param n Determines the line and char position within the source file name * @

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>); } public static Node hook(Node cond, Node trueval, Node falseval) { Preconditions.checkState(mayBeExpression(cond)); Preconditions.checkState(mayBeExpression(trueval)); Preconditions.checkState(mayBeExpression(falseval)); return new Node(Token.HOOK, cond, trueval, falseval); } public static Node comma(Node expr1, Node expr2) { return binaryOp(Token.COMMA, expr1, expr2); } public static Node and(Node expr1, Node expr2) { return binaryOp(Token.AND, expr1, expr2); } public static Node or(Node expr1, Node expr2) { return binaryOp(Token.OR, expr1, expr2); } public static Node not(Node expr1) { return unaryOp(Token.NOT, expr1); } /** * "==" */ public static Node eq(Node expr1, Node expr2) { return binaryOp(Token.EQ, expr1, expr2); } /** * "===" */ public static Node sheq(Node expr1, Node expr2) { return binaryOp(Token.SHEQ, expr1, expr2); } public static Node voidNode(Node expr1) { return unaryOp(Token.VOID, expr1); } public static Node neg(Node expr1) { return unaryOp(Token.NEG, expr1); } public static Node pos(Node expr1) { return unaryOp(Token.POS, expr1); } public static Node add(Node expr1, Node expr2) { return binaryOp(Token.ADD, expr1, expr2); } public static Node sub(Node expr1, Node expr2) { return binaryOp(Token.SUB, expr1, expr2); } // TODO(johnlenz): the rest of the ops // literals public static Node objectlit(Node ... propdefs) { Node objectlit = new Node(Token.OBJECTLIT); for (Node propdef : propdefs) { Preconditions.checkState( propdef.isString() || propdef.isGetterDef() || propdef.isSetterDef()); Preconditions.checkState(

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>Guard a, WarningsGuard b) { int priorityDiff = a.getPriority() - b.getPriority(); if (priorityDiff != 0) { return priorityDiff; } // If the warnings guards have the same priority, the one that // was added last wins. return orderOfAddition.get(b).intValue() - orderOfAddition.get(a).intValue(); } } // The order that the guards are applied in. private final TreeSet<WarningsGuard> guards = new TreeSet<WarningsGuard>(guardComparator); public ComposeWarningsGuard(List<WarningsGuard> guards) { addGuards(guards); } public ComposeWarningsGuard(WarningsGuard... guards) { this(Lists.newArrayList(guards)); } void addGuard(WarningsGuard guard) { if (guard instanceof ComposeWarningsGuard) { // Reverse the guards, so that they have the same order in the result. addGuards(((ComposeWarningsGuard) guard).guards.descendingSet()); } else { numberOfAdds++; orderOfAddition.put(guard, numberOfAdds); guards.remove(guard); guards.add(guard); } } private void addGuards(Iterable<WarningsGuard> guards) { for (WarningsGuard guard : guards) { addGuard(guard); } } @Override public CheckLevel level(JSError error) { for (WarningsGuard guard : guards) { CheckLevel newLevel = guard.level(error); if (newLevel != null) { return newLevel; } } return null; } @Override public boolean disables(DiagnosticGroup group) { nextSingleton: for (DiagnosticType type : group.getTypes()) { DiagnosticGroup singleton = DiagnosticGroup.forType(type); for (WarningsGuard guard : guards) { if (guard.disables(singleton)) { continue nextSingleton; } else if (guard.enables(singleton)) { return false; } } return false; } return true; } /** * Determines whether this guard will "elevate" the status of any disabled * diagnostic type in the group to a warning or an error. */

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>/* * Copyright 2007 The Closure Compiler Authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.collect.Sets; import com.google.javascript.jscomp.CheckLevel; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.SortedSet; /** * <p>A basic error manager that sorts all errors and warnings reported to it to * generate a sorted report when the {@link #generateReport()} method * is called.</p> * * <p>This error manager does not produce any output, but subclasses can * override the {@link #println(CheckLevel, JSError)} method to generate custom * output.</p> * */ public abstract class BasicErrorManager implements ErrorManager { private final SortedSet<ErrorWithLevel> messages = Sets.newTreeSet(new LeveledJSErrorComparator()); private int errorCount = 0; private int warningCount = 0; private double typedPercent = 0.0; @Override public void report(CheckLevel level, JSError error) { if (messages.add(new ErrorWithLevel(error, level))) { if (level == CheckLevel.ERROR) { errorCount++; } else if (level == CheckLevel.WARNING) { warningCount++; } } } @Override public void generateReport() { for (ErrorWithLevel message : messages) { println(message.level, message.error); } printSummary(); } /** * Print a message with a trailing new line. This method is called by the *

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> {@link #generateReport()} method when generating messages. */ public abstract void println(CheckLevel level, JSError error); /** * Print the summary of the compilation - number of errors and warnings. */ protected abstract void printSummary(); @Override public int getErrorCount() { return errorCount; } @Override public int getWarningCount() { return warningCount; } @Override public JSError[] getErrors() { return toArray(CheckLevel.ERROR); } @Override public JSError[] getWarnings() { return toArray(CheckLevel.WARNING); } @Override public void setTypedPercent(double typedPercent) { this.typedPercent = typedPercent; } @Override public double getTypedPercent() { return typedPercent; } private JSError[] toArray(CheckLevel level) { List<JSError> errors = new ArrayList<JSError>(messages.size()); for (ErrorWithLevel p : messages) { if (p.level == level) { errors.add(p.error); } } return errors.toArray(new JSError[errors.size()]); } /** * <p>Comparator of {@link JSError} with an associated {@link CheckLevel}. * The ordering is the standard lexical ordering on the quintuple * (file name, line number, {@link CheckLevel}, * character number, description).</p> * * <p>Note: this comparator imposes orderings that are inconsistent with * {@link JSError#equals(Object)}.</p> */ static final class LeveledJSErrorComparator implements Comparator<ErrorWithLevel> { private static final int P1_LT_P2 = -1; private static final int P1_GT_P2 = 1; @Override public int compare(ErrorWithLevel p1, ErrorWithLevel p2) { // null is the smallest value if (p2 == null) { if (p1 == null) { return 0; } else { return P1_GT_P2; } } // check level if (p1.level != p2.level) { return p2.level.compareTo(p1.level

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> private boolean frozen = false; // The last slot defined in this flow instruction, and the head of the // linked list of slots. private LinkedFlowSlot lastSlot; private LinkedFlowScope(FlatFlowScopeCache cache, LinkedFlowScope directParent) { this.cache = cache; if (directParent == null) { this.lastSlot = null; this.depth = 0; this.parent = cache.linkedEquivalent; } else { this.lastSlot = directParent.lastSlot; this.depth = directParent.depth + 1; this.parent = directParent; } } LinkedFlowScope(FlatFlowScopeCache cache) { this(cache, null); } LinkedFlowScope(LinkedFlowScope directParent) { this(directParent.cache, directParent); } /** Gets the function scope for this flow scope. */ private Scope getFunctionScope() { return cache.functionScope; } /** Whether this flows from a bottom scope. */ private boolean flowsFromBottom() { return getFunctionScope().isBottom(); } /** * Creates an entry lattice for the flow. */ public static LinkedFlowScope createEntryLattice(Scope scope) { return new LinkedFlowScope(new FlatFlowScopeCache(scope)); } @Override public void inferSlotType(String symbol, JSType type) { Preconditions.checkState(!frozen); lastSlot = new LinkedFlowSlot(symbol, type, lastSlot); depth++; cache.dirtySymbols.add(symbol); } @Override public void inferQualifiedSlot(Node node, String symbol, JSType bottomType, JSType inferredType) { Scope functionScope = getFunctionScope(); if (functionScope.isLocal()) { if (functionScope.getVar(symbol) == null && !functionScope.isBottom()) { functionScope.declare(symbol, node, bottomType, null); } inferSlotType(symbol, inferredType); } } @Override public JSType getTypeOfThis() { return cache.functionScope.getTypeOfThis(); } @Override public Node getRootNode() { return getFunctionScope().getRootNode(); } @Override public StaticScope<JSType> getParentScope()

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> both 0 based. int lineBaseOffset = 1; if (generator instanceof SourceMapGeneratorV1 || generator instanceof SourceMapGeneratorV2) { lineBaseOffset = 0; } generator.addMapping( sourceFile, originalName, new FilePosition(node.getLineno() - lineBaseOffset, node.getCharno()), outputStartPosition, outputEndPosition); } /** * @param sourceFile The source file location to fixup. * @return a remapped source file. */ private String fixupSourceLocation(String sourceFile) { if (prefixMappings.isEmpty()) { return sourceFile; } String fixed = sourceLocationFixupCache.get(sourceFile); if (fixed != null) { return fixed; } // Replace the first prefix found with its replacement for (LocationMapping mapping : prefixMappings) { if (sourceFile.startsWith(mapping.prefix)) { fixed = mapping.replacement + sourceFile.substring( mapping.prefix.length()); break; } } // If none of the mappings match then use the original file path. if (fixed == null) { fixed = sourceFile; } sourceLocationFixupCache.put(sourceFile, fixed); return fixed; } public void appendTo(Appendable out, String name) throws IOException { generator.appendTo(out, name); } public void reset() { generator.reset(); sourceLocationFixupCache.clear(); } public void setStartingPosition(int offsetLine, int offsetIndex) { generator.setStartingPosition(offsetLine, offsetIndex); } public void setWrapperPrefix(String prefix) { generator.setWrapperPrefix(prefix); } public void validate(boolean validate) { generator.validate(validate); } /** * @param sourceMapLocationMappings */ public void setPrefixMappings(List<LocationMapping> sourceMapLocationMappings) { this.prefixMappings = sourceMapLocationMappings; } }

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> * Lists of modules at each depth. <code>modulesByDepth.get(3)</code> is a * list of the modules at depth 3, for example. */ private List<List<JSModule>> modulesByDepth; /** * dependencyMap is a cache of dependencies that makes the dependsOn * function faster. Each map entry associates a starting * JSModule with the set of JSModules that are transitively dependent on the * starting module. * * If the cache returns null, then the entry hasn't been filled in for that * module. * * dependencyMap should be filled from leaf to root so that * getTransitiveDepsDeepestFirst can use its results directly. */ private Map<JSModule, Set<JSModule>> dependencyMap = Maps.newHashMap(); /** * Creates a module graph from a list of modules in dependency order. */ public JSModuleGraph(JSModule[] modulesInDepOrder) { this(Lists.<JSModule>newArrayList(modulesInDepOrder)); } /** * Creates a module graph from a list of modules in dependency order. */ public JSModuleGraph(List<JSModule> modulesInDepOrder) { modules = Sets.newHashSetWithExpectedSize(modulesInDepOrder.size()); modulesByDepth = Lists.newArrayList(); for (JSModule module : modulesInDepOrder) { int depth = 0; for (JSModule dep : module.getDependencies()) { int depDepth = dep.getDepth(); if (depDepth < 0) { throw new ModuleDependenceException(String.format( "Modules not in dependency order: %s preceded %s", module.getName(), dep.getName()), module, dep); } depth = Math.max(depth, depDepth + 1); } module.setDepth(depth); modules.add(module); if (depth == modulesByDepth.size()) { modulesByDepth.add(new ArrayList<JSModule>()); } modulesByDepth.get(depth).add(module); } } /** * Gets an iterable over all modules. */ Iterable<JSModule> getAllModules() { return modules; } /** * Gets all the modules in dependency order. Modules

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> (dependsOn(m1, m) && dependsOn(m2, m)) { return m; } } } return null; } /** * Finds the deepest common dependency of two modules, including the * modules themselves. * * @param m1 A module in this graph * @param m2 A module in this graph * @return The deepest common dep of {@code m1} and {@code m2}, or null if * they have no common dependencies */ public JSModule getDeepestCommonDependencyInclusive( JSModule m1, JSModule m2) { if (m2 == m1 || dependsOn(m2, m1)) { return m1; } else if (dependsOn(m1, m2)) { return m2; } return getDeepestCommonDependency(m1, m2); } /** Returns the deepest common dependency of the given modules. */ public JSModule getDeepestCommonDependencyInclusive( Collection<JSModule> modules) { Iterator<JSModule> iter = modules.iterator(); JSModule dep = iter.next(); while (iter.hasNext()) { dep = getDeepestCommonDependencyInclusive(dep, iter.next()); } return dep; } /** * Creates an iterable over the transitive dependencies of module {@code m} * in a non-increasing depth ordering. The result does not include the module * {@code m}. * * @param m A module in this graph * @return The transitive dependencies of module {@code m} */ Set<JSModule> getTransitiveDepsDeepestFirst(JSModule m) { Set<JSModule> deps = dependencyMap.get(m); if (deps != null) { return deps; } deps = new TreeSet<JSModule>(new InverseDepthComparator()); addDeps(deps, m); dependencyMap.put(m, deps); return deps; } /** * Adds a module's transitive dependencies to a set. */ private void addDeps(Set<JSModule> deps, JSModule m) { for (JSModule dep : m.getDependencies()) { deps.add(dep); add

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>Deps(deps, dep); } } /** * Replaces any files that are found multiple times with a single instance in * the closest parent module that is common to all modules where it appears. * * JSCompiler normally errors if you attempt to compile modules containing the * same file. This method can be used to remove duplicates before compiling * to avoid such an error. */ public void coalesceDuplicateFiles() { Multimap<String, JSModule> fileRefs = LinkedHashMultimap.create(); for (JSModule module : modules) { for (CompilerInput jsFile : module.getInputs()) { fileRefs.put(jsFile.getName(), module); } } for (String path : fileRefs.keySet()) { Collection<JSModule> refModules = fileRefs.get(path); if (refModules.size() > 1) { JSModule depModule = getDeepestCommonDependencyInclusive(refModules); CompilerInput file = refModules.iterator().next().getByName(path); for (JSModule module : refModules) { if (module != depModule) { module.removeByName(path); } } if (!refModules.contains(depModule)) { depModule.add(file); } } } } /** * Applies a DependencyOptions in "dependency sorting" and "dependency pruning" * mode to the given list of inputs. Returns a new list with the files sorted * and removed. This module graph will be updated to reflect the new list. * * If you need more fine-grained dependency management, you should create your * own DependencyOptions and call * {@code manageDependencies(DependencyOptions, List<CompilerInput>)}. * * @param entryPoints The entry points into the program. * Expressed as JS symbols. * @param inputs The original list of sources. Used to ensure that the sort * is stable. * @throws CircularDependencyException if there is a circular dependency * between the provides and requires. * @throws MissingProvideException if an entry point was not provided * by any of the inputs. * @see DependencyOptions for more info on how this works. */ public List<CompilerInput> manageDependencies( List<String> entry

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>Points, List<CompilerInput> inputs) throws CircularDependencyException, MissingProvideException { DependencyOptions depOptions = new DependencyOptions(); depOptions.setDependencySorting(true); depOptions.setDependencyPruning(true); depOptions.setEntryPoints(entryPoints); return manageDependencies(depOptions, inputs); } /** * Apply the dependency options to the list of sources, returning a new * source list re-ordering and dropping files as necessary. * This module graph will be updated to reflect the new list. * * @param inputs The original list of sources. Used to ensure that the sort * is stable. * @throws CircularDependencyException if there is a circular dependency * between the provides and requires. * @throws MissingProvideException if an entry point was not provided * by any of the inputs. * @see DependencyOptions for more info on how this works. */ public List<CompilerInput> manageDependencies( DependencyOptions depOptions, List<CompilerInput> inputs) throws CircularDependencyException, MissingProvideException { SortedDependencies<CompilerInput> sorter = new SortedDependencies<CompilerInput>(inputs); Set<CompilerInput> entryPointInputs = Sets.newLinkedHashSet(); if (depOptions.shouldPruneDependencies()) { if (!depOptions.shouldDropMoochers()) { entryPointInputs.addAll(sorter.getInputsWithoutProvides()); } for (String entryPoint : depOptions.getEntryPoints()) { entryPointInputs.add(sorter.getInputProviding(entryPoint)); } } else { entryPointInputs.addAll(inputs); } // The order of inputs, sorted independently of modules. List<CompilerInput> absoluteOrder = sorter.getDependenciesOf(inputs, depOptions.shouldSortDependencies()); // Figure out which sources *must* be in each module. ListMultimap<JSModule, CompilerInput> entryPointInputsPerModule = LinkedListMultimap.create(); for (CompilerInput input : entryPointInputs) { JSModule module = input.getModule(); Preconditions.checkNotNull(module); entryPointInputsPerModule.put(module, input); } // Clear the modules of their inputs. This also nulls out // the input's reference to its module. for (JS

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>Module module : getAllModules()) { module.removeAll(); } // Figure out which sources *must* be in each module, or in one // of that module's dependencies. for (JSModule module : entryPointInputsPerModule.keySet()) { List<CompilerInput> transitiveClosure = sorter.getDependenciesOf( entryPointInputsPerModule.get(module), depOptions.shouldSortDependencies()); for (CompilerInput input : transitiveClosure) { JSModule oldModule = input.getModule(); if (oldModule == null) { input.setModule(module); } else { input.setModule(null); input.setModule( getDeepestCommonDependencyInclusive(oldModule, module)); } } } // All the inputs are pointing to the modules that own them. Yeah! // Update the modules to reflect this. for (CompilerInput input : absoluteOrder) { JSModule module = input.getModule(); if (module != null) { module.add(input); } } // Now, generate the sorted result. List<CompilerInput> result = Lists.newArrayList(); for (JSModule module : getAllModulesInDependencyOrder()) { result.addAll(module.getInputs()); } return result; } LinkedDirectedGraph<JSModule, String> toGraphvizGraph() { LinkedDirectedGraph<JSModule, String> graphViz = LinkedDirectedGraph.create(); for (JSModule module : getAllModulesInDependencyOrder()) { graphViz.createNode(module); for (JSModule dep : module.getDependencies()) { graphViz.createNode(dep); graphViz.connect(module, "->", dep); } } return graphViz; } /** * A module depth comparator that considers a deeper module to be * "greater than" a shallower module. Uses module names to * consistently break ties. */ private class DepthComparator implements Comparator<JSModule> { @Override public int compare(JSModule m1, JSModule m2) { return depthCompare(m1, m2); } } /** * A module depth comparator that considers a deeper module to be "less than" * a shallower module. Uses module names to

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> to prevent * a variable from getting renamed, but no longer have any effect. */ private class NameRefInExternsCheck extends AbstractPostOrderCallback { @Override public void visit(NodeTraversal t, Node n, Node parent) { if (n.isName()) { switch (parent.getType()) { case Token.VAR: case Token.FUNCTION: case Token.PARAM_LIST: // These are okay. break; case Token.GETPROP: if (n == parent.getFirstChild()) { Scope scope = t.getScope(); Scope.Var var = scope.getVar(n.getString()); if (var == null) { t.report(n, UNDEFINED_EXTERN_VAR_ERROR, n.getString()); varsToDeclareInExterns.add(n.getString()); } } break; default: t.report(n, NAME_REFERENCE_IN_EXTERNS_ERROR, n.getString()); Scope scope = t.getScope(); Scope.Var var = scope.getVar(n.getString()); if (var == null) { varsToDeclareInExterns.add(n.getString()); } break; } } } } /** Lazily create a "new" externs input for undeclared variables. */ private CompilerInput getSynthesizedExternsInput() { return compiler.getSynthesizedExternsInput(); } /** Lazily create a "new" externs root for undeclared variables. */ private Node getSynthesizedExternsRoot() { if (synthesizedExternsRoot == null) { CompilerInput synthesizedExterns = getSynthesizedExternsInput(); synthesizedExternsRoot = synthesizedExterns.getAstRoot(compiler); } return synthesizedExternsRoot; } }

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> this.depth = -1; } /** Gets the module name. */ @Override public String getName() { return name; } @Override public List<String> getProvides() { return ImmutableList.<String>of(name); } @Override public List<String> getRequires() { ImmutableList.Builder<String> builder = ImmutableList.builder(); for (JSModule m : deps) { builder.add(m.getName()); } return builder.build(); } @Override public String getPathRelativeToClosureBase() { throw new UnsupportedOperationException(); } /** Adds a source file input to this module. */ public void add(JSSourceFile file) { add(new CompilerInput(file)); } /** Adds a source file input to this module. */ public void addFirst(JSSourceFile file) { addFirst(new CompilerInput(file)); } /** Adds a source code input to this module. */ public void add(CompilerInput input) { inputs.add(input); input.setModule(this); } /** * Adds a source code input to this module. Call only if the input might * already be associated with a module. Otherwise use * add(CompilerInput input). */ void addAndOverrideModule(CompilerInput input) { inputs.add(input); input.overrideModule(this); } /** Adds a source code input to this module. */ public void addFirst(CompilerInput input) { inputs.add(0, input); input.setModule(this); } /** Adds a source code input to this module directly after other. */ public void addAfter(CompilerInput input, CompilerInput other) { Preconditions.checkState(inputs.contains(other)); inputs.add(inputs.indexOf(other), input); input.setModule(this); } /** Adds a dependency on another module. */ public void addDependency(JSModule dep) { Preconditions.checkState(dep != this); deps.add(dep); } /** Removes an input from this module. */ public void remove(CompilerInput input) { input.setModule(null); inputs.remove(input); } /** Removes all of the inputs from this module. */

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> public void removeAll() { for (CompilerInput input : inputs) { input.setModule(null); } inputs.clear(); } /** * Gets the list of modules that this module depends on. * * @return A list that may be empty but not null */ public List<JSModule> getDependencies() { return deps; } /** * Gets the names of the modules that this module depends on, * sorted alphabetically. */ List<String> getSortedDependencyNames() { List<String> names = Lists.newArrayList(); for (JSModule module : getDependencies()) { names.add(module.getName()); } Collections.sort(names); return names; } /** * Returns the transitive closure of dependencies starting from the * dependencies of this module. */ public Set<JSModule> getAllDependencies() { Set<JSModule> allDeps = Sets.newHashSet(deps); List<JSModule> workList = Lists.newArrayList(deps); while (workList.size() > 0) { JSModule module = workList.remove(workList.size() - 1); for (JSModule dep : module.getDependencies()) { if (allDeps.add(dep)) { workList.add(dep); } } } return allDeps; } /** Returns this module and all of its dependencies in one list. */ public Set<JSModule> getThisAndAllDependencies() { Set<JSModule> deps = getAllDependencies(); deps.add(this); return deps; } /** * Gets this module's list of source code inputs. * * @return A list that may be empty but not null */ public List<CompilerInput> getInputs() { return inputs; } /** Returns the input with the given name or null if none. */ public CompilerInput getByName(String name) { for (CompilerInput input : inputs) { if (name.equals(input.getName())) { return input; } } return null; } /** * Removes any input with the given name. Returns whether any were removed. */ public boolean removeByName(String name) { boolean found = false; Iterator<Compiler

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>Input> iter = inputs.iterator(); while (iter.hasNext()) { CompilerInput file = iter.next(); if (name.equals(file.getName())) { iter.remove(); file.setModule(null); found = true; } } return found; } /** Returns the module name (primarily for debugging). */ @Override public String toString() { return name; } /** * Removes any references to nodes of the AST. This method is needed to * allow the ASTs to be garbage collected if the modules are kept around. */ public void clearAsts() { for (CompilerInput input : inputs) { input.clearAst(); } } /** * Puts the JS files into a topologically sorted order by their dependencies. */ public void sortInputsByDeps(Compiler compiler) { // Set the compiler, so that we can parse requires/provides and report // errors properly. for (CompilerInput input : inputs) { input.setCompiler(compiler); } // Sort the JSModule in this order. try { List<CompilerInput> sortedList = (new SortedDependencies<CompilerInput>( Collections.<CompilerInput>unmodifiableList(inputs))) .getSortedList(); inputs.clear(); inputs.addAll(sortedList); } catch (CircularDependencyException e) { compiler.report( JSError.make(CIRCULAR_DEPENDENCY_ERROR, e.getMessage())); } } /** * Returns the given collection of modules in topological order. * * Note that this will return the modules in the same order if they are * already sorted, and in general, will only change the order as necessary to * satisfy the ordering dependencies. This can be important for cases where * the modules do not properly specify all dependencies. */ public static JSModule[] sortJsModules(Collection<JSModule> modules) throws CircularDependencyException { // Sort the JSModule in this order. List<JSModule> sortedList = (new SortedDependencies<JSModule>( Lists.newArrayList(modules))).getSortedList(); return sortedList.toArray(new JSModule[sortedList.size()]); } /** * @param dep the depth to set */ public void setDepth

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>return true if this node marks the start of a new basic block */ private static boolean isBlockBoundary(Node n, Node parent) { if (parent != null) { switch (parent.getType()) { case Token.DO: case Token.FOR: case Token.TRY: case Token.WHILE: case Token.WITH: // NOTE: TRY has up to 3 child blocks: // TRY // BLOCK // BLOCK // CATCH // BLOCK // Note that there is an explcit CATCH token but no explicit // FINALLY token. For simplicity, we consider each BLOCK // a separate basic BLOCK. return true; case Token.AND: case Token.HOOK: case Token.IF: case Token.OR: // The first child of a conditional is not a boundary, // but all the rest of the children are. return n != parent.getFirstChild(); } } return n.isCase(); } private void addReference(NodeTraversal t, Var v, Reference reference) { // Create collection if none already ReferenceCollection referenceInfo = referenceMap.get(v); if (referenceInfo == null) { referenceInfo = new ReferenceCollection(); referenceMap.put(v, referenceInfo); } // Add this particular reference referenceInfo.add(reference, t, v); } interface ReferenceMap { ReferenceCollection getReferences(Var var); } private static class ReferenceMapWrapper implements ReferenceMap { private final Map<Var, ReferenceCollection> referenceMap; public ReferenceMapWrapper(Map<Var, ReferenceCollection> referenceMap) { this.referenceMap = referenceMap; } @Override public ReferenceCollection getReferences(Var var) { return referenceMap.get(var); } } /** * Way for callers to add specific behavior during traversal that * utilizes the built-up reference information. */ interface Behavior { /** * Called after we finish with a scope. */ void afterExitScope(NodeTraversal t, ReferenceMap referenceMap); } static Behavior DO_NOTHING_BEHAVIOR = new Behavior() { @Override public void afterExitScope(NodeTraversal t, ReferenceMap referenceMap) {} }; /** * A collection of

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> references. Can be subclassed to apply checks or * store additional state when adding. */ static class ReferenceCollection implements Iterable<Reference> { List<Reference> references = Lists.newArrayList(); @Override public Iterator<Reference> iterator() { return references.iterator(); } void add(Reference reference, NodeTraversal t, Var v) { references.add(reference); } /** * Determines if the variable for this reference collection is * "well-defined." A variable is well-defined if we can prove at * compile-time that it's assigned a value before it's used. * * Notice that if this function returns false, this doesn't imply that the * variable is used before it's assigned. It just means that we don't * have enough information to make a definitive judgement. */ protected boolean isWellDefined() { int size = references.size(); if (size == 0) { return false; } // If this is a declaration that does not instantiate the variable, // it's not well-defined. Reference init = getInitializingReference(); if (init == null) { return false; } Preconditions.checkState(references.get(0).isDeclaration()); BasicBlock initBlock = init.getBasicBlock(); for (int i = 1; i < size; i++) { if (!initBlock.provablyExecutesBefore( references.get(i).getBasicBlock())) { return false; } } return true; } /** * Whether the variable is escaped into an inner scope. */ boolean isEscaped() { Scope scope = null; for (Reference ref : references) { if (scope == null) { scope = ref.scope; } else if (scope != ref.scope) { return true; } } return false; } /** * @param index The index into the references array to look for an * assigning declaration. * * This is either the declaration if a value is assigned (such as * "var a = 2", "function a()...", "... catch (a)..."). */ private boolean isInitializingDeclarationAt(int index) { Reference maybeInit = references.get(index); if (maybeInit

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>(); if (baseConstructor != null && baseConstructor != getNativeType(OBJECT_FUNCTION_TYPE) && (baseConstructor.isInterface() && functionType.isConstructor())) { compiler.report( t.makeError(n, CONFLICTING_EXTENDED_TYPE, functionPrivateName)); } else { // All interfaces are properly implemented by a class for (JSType baseInterface : functionType.getImplementedInterfaces()) { boolean badImplementedType = false; ObjectType baseInterfaceObj = ObjectType.cast(baseInterface); if (baseInterfaceObj != null) { FunctionType interfaceConstructor = baseInterfaceObj.getConstructor(); if (interfaceConstructor != null && !interfaceConstructor.isInterface()) { badImplementedType = true; } } else { badImplementedType = true; } if (badImplementedType) { report(t, n, BAD_IMPLEMENTED_TYPE, functionPrivateName); } } // check properties validator.expectAllInterfaceProperties(t, n, functionType); } } else if (functionType.isInterface()) { // Interface must extend only interfaces for (ObjectType extInterface : functionType.getExtendedInterfaces()) { if (extInterface.getConstructor() != null && !extInterface.getConstructor().isInterface()) { compiler.report( t.makeError(n, CONFLICTING_EXTENDED_TYPE, functionPrivateName)); } } // Interface cannot implement any interfaces if (functionType.hasImplementedInterfaces()) { compiler.report(t.makeError(n, CONFLICTING_IMPLEMENTED_TYPE, functionPrivateName)); } // Check whether the extended interfaces have any conflicts if (functionType.getExtendedInterfacesCount() > 1) { // Only check when extending more than one interfaces HashMap<String, ObjectType> properties = new HashMap<String, ObjectType>(); HashMap<String, ObjectType> currentProperties = new HashMap<String, ObjectType>(); for (ObjectType interfaceType : functionType.getExtendedInterfaces()) { currentProperties.clear(); checkInterfaceConflictProperties(t, n, functionPrivateName, properties, currentProperties, interfaceType); properties.putAll(currentProperties); } } } } /** * Visits a CALL node.

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> jsDocParser) { if (jsDocParser.getFileOverviewJSDocInfo() != fileOverviewInfo) { fileOverviewInfo = jsDocParser.getFileOverviewJSDocInfo(); return true; } return false; } private void handlePossibleFileOverviewJsDoc(Comment comment, Node irNode) { JsDocInfoParser jsDocParser = createJsDocInfoParser(comment, irNode); parsedComments.add(comment); handlePossibleFileOverviewJsDoc(jsDocParser); } private JSDocInfo handleJsDoc(AstNode node, Node irNode) { Comment comment = node.getJsDocNode(); if (comment != null) { JsDocInfoParser jsDocParser = createJsDocInfoParser(comment, irNode); parsedComments.add(comment); if (!handlePossibleFileOverviewJsDoc(jsDocParser)) { return jsDocParser.retrieveAndResetParsedJSDocInfo(); } } return null; } private Node transform(AstNode node) { Node irNode = justTransform(node); JSDocInfo jsDocInfo = handleJsDoc(node, irNode); if (jsDocInfo != null) { irNode.setJSDocInfo(jsDocInfo); } setSourceInfo(irNode, node); return irNode; } private Node transformNameAsString(Name node) { Node irNode = transformDispatcher.processName(node, true); JSDocInfo jsDocInfo = handleJsDoc(node, irNode); if (jsDocInfo != null) { irNode.setJSDocInfo(jsDocInfo); } setSourceInfo(irNode, node); return irNode; } private Node transformNumberAsString(NumberLiteral literalNode) { Node irNode = newStringNode(getStringValue(literalNode.getNumber())); JSDocInfo jsDocInfo = handleJsDoc(literalNode, irNode); if (jsDocInfo != null) { irNode.setJSDocInfo(jsDocInfo); } setSourceInfo(irNode, literalNode); return irNode; } private static String getStringValue(double value) { long longValue = (long) value; // Return "1" instead of

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>child); node.addChildToBack(c); } return node; } @Override Node processAssignment(Assignment assignmentNode) { Node assign = processInfixExpression(assignmentNode); Node target = assign.getFirstChild(); if (!validAssignmentTarget(target)) { errorReporter.error( "invalid assignment target", sourceName, target.getLineno(), "", 0); } return assign; } @Override Node processAstRoot(AstRoot rootNode) { Node node = newNode(Token.SCRIPT); for (com.google.javascript.rhino.head.Node child : rootNode) { node.addChildToBack(transform((AstNode)child)); } parseDirectives(node); return node; } /** * Parse the directives, encode them in the AST, and remove their nodes. * * For information on ES5 directives, see section 14.1 of * Ecma-262, Edition 5. * * It would be nice if Rhino would eventually take care of this for * us, but right now their directive-processing is a one-off. */ private void parseDirectives(Node node) { // Remove all the directives, and encode them in the AST. Set<String> directives = null; while (isDirective(node.getFirstChild())) { String directive = node.removeFirstChild().getFirstChild().getString(); if (directives == null) { directives = Sets.newHashSet(directive); } else { directives.add(directive); } } if (directives != null) { node.setDirectives(directives); } } private boolean isDirective(Node n) { if (n == null) return false; int nType = n.getType(); return nType == Token.EXPR_RESULT && n.getFirstChild().isString() && ALLOWED_DIRECTIVES.contains(n.getFirstChild().getString()); } @Override Node processBlock(Block blockNode) { return processGeneric(blockNode); } @Override Node processBreakStatement(BreakStatement statementNode) { Node node = newNode(Token.BREAK); if (statementNode.getBreakLabel() != null) { Node labelName =

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> // A list of all the inputs that do not have provides. private final List<INPUT> noProvides; private final Map<String, INPUT> provideMap = Maps.newHashMap(); public SortedDependencies(List<INPUT> inputs) throws CircularDependencyException { this.inputs = Lists.newArrayList(inputs); noProvides = Lists.newArrayList(); // Collect all symbols provided in these files. for (INPUT input : inputs) { Collection<String> currentProvides = input.getProvides(); if (currentProvides.isEmpty()) { noProvides.add(input); } for (String provide : currentProvides) { provideMap.put(provide, input); } } // Get the direct dependencies. final Multimap<INPUT, INPUT> deps = HashMultimap.create(); for (INPUT input : inputs) { for (String req : input.getRequires()) { INPUT dep = provideMap.get(req); if (dep != null) { deps.put(input, dep); } } } // Sort the inputs by sucking in 0-in-degree nodes until we're done. sortedList = topologicalStableSort(inputs, deps); // The dependency graph of inputs has a cycle iff sortedList is a proper // subset of inputs. Also, it has a cycle iff the subgraph // (inputs - sortedList) has a cycle. It's fairly easy to prove this // by the lemma that a graph has a cycle iff it has a subgraph where // no nodes have out-degree 0. I'll leave the proof of this as an exercise // to the reader. if (sortedList.size() < inputs.size()) { List<INPUT> subGraph = Lists.newArrayList(inputs); subGraph.removeAll(sortedList); throw new CircularDependencyException( cycleToString(findCycle(subGraph, deps))); } } /** * Return the input that gives us the given symbol. * @throws MissingProvideException An exception if there is no * input for this symbol. */ public INPUT getInputProviding(String symbol) throws MissingProvideException { if (provideMap.containsKey(symbol)) { return provideMap.get(symbol); } throw new MissingProvideException(symbol); } /**

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> * Returns the first circular dependency found. Expressed as a list of * items in reverse dependency order (the second element depends on the * first, etc.). */ private List<INPUT> findCycle( List<INPUT> subGraph, Multimap<INPUT, INPUT> deps) { return findCycle(subGraph.get(0), Sets.<INPUT>newHashSet(subGraph), deps, Sets.<INPUT>newHashSet()); } private List<INPUT> findCycle( INPUT current, Set<INPUT> subGraph, Multimap<INPUT, INPUT> deps, Set<INPUT> covered) { if (covered.add(current)) { List<INPUT> cycle = findCycle( findRequireInSubGraphOrFail(current, subGraph), subGraph, deps, covered); // Don't add the input to the list if the cycle has closed already. if (cycle.get(0) != cycle.get(cycle.size() - 1)) { cycle.add(current); } return cycle; } else { // Explicitly use the add() method, to prevent a generics constructor // warning that is dumb. The condition it's protecting is // obscure, and I think people have proposed that it be removed. List<INPUT> cycle = Lists.<INPUT>newArrayList(); cycle.add(current); return cycle; } } private INPUT findRequireInSubGraphOrFail(INPUT input, Set<INPUT> subGraph) { for (String symbol : input.getRequires()) { INPUT candidate = provideMap.get(symbol); if (subGraph.contains(candidate)) { return candidate; } } throw new IllegalStateException("no require found in subgraph"); } /** * @param cycle A cycle in reverse-dependency order. */ private String cycleToString(List<INPUT> cycle) { List<String> symbols = Lists.newArrayList(); for (int i = cycle.size() - 1; i >= 0; i--) { symbols.add(cycle.get(i).getProvides().iterator().next()); } symbols.add(symbols.get(0)); return Joiner.on(" -> ").join(symbols); } public List<INPUT> getSortedList() { return Collections

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>.<INPUT>unmodifiableList(sortedList); } /** * Gets all the dependencies of the given roots. The inputs must be returned * in a stable order. In other words, if A comes before B, and A does not * transitively depend on B, then A must also come before B in the returned * list. */ public List<INPUT> getSortedDependenciesOf(List<INPUT> roots) { return getDependenciesOf(roots, true); } /** * Gets all the dependencies of the given roots. The inputs must be returned * in a stable order. In other words, if A comes before B, and A does not * transitively depend on B, then A must also come before B in the returned * list. * * @param sorted If true, get them in topologically sorted order. If false, * get them in the original order they were passed to the compiler. */ public List<INPUT> getDependenciesOf(List<INPUT> roots, boolean sorted) { Preconditions.checkArgument(inputs.containsAll(roots)); Set<INPUT> included = Sets.newHashSet(); Deque<INPUT> worklist = new ArrayDeque<INPUT>(roots); while (!worklist.isEmpty()) { INPUT current = worklist.pop(); if (included.add(current)) { for (String req : current.getRequires()) { INPUT dep = provideMap.get(req); if (dep != null) { worklist.add(dep); } } } } ImmutableList.Builder<INPUT> builder = ImmutableList.builder(); for (INPUT current : (sorted ? sortedList : inputs)) { if (included.contains(current)) { builder.add(current); } } return builder.build(); } public List<INPUT> getInputsWithoutProvides() { return Collections.<INPUT>unmodifiableList(noProvides); } private static <T> List<T> topologicalStableSort( List<T> items, Multimap<T, T> deps) { if (items.size() == 0) { // Priority queue blows up if we give it a size of 0. Since we need // to special case this either way, just bail out. return Lists.newArrayList();

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> } final Map<T, Integer> originalIndex = Maps.newHashMap(); for (int i = 0; i < items.size(); i++) { originalIndex.put(items.get(i), i); } PriorityQueue<T> inDegreeZero = new PriorityQueue<T>(items.size(), new Comparator<T>() { @Override public int compare(T a, T b) { return originalIndex.get(a).intValue() - originalIndex.get(b).intValue(); } }); List<T> result = Lists.newArrayList(); Multiset<T> inDegree = HashMultiset.create(); Multimap<T, T> reverseDeps = ArrayListMultimap.create(); Multimaps.invertFrom(deps, reverseDeps); // First, add all the inputs with in-degree 0. for (T item : items) { Collection<T> itemDeps = deps.get(item); inDegree.add(item, itemDeps.size()); if (itemDeps.isEmpty()) { inDegreeZero.add(item); } } // Then, iterate to a fixed point over the reverse dependency graph. while (!inDegreeZero.isEmpty()) { T item = inDegreeZero.remove(); result.add(item); for (T inWaiting : reverseDeps.get(item)) { inDegree.remove(inWaiting, 1); if (inDegree.count(inWaiting) == 0) { inDegreeZero.add(inWaiting); } } } return result; } public static class CircularDependencyException extends Exception { CircularDependencyException(String message) { super(message); } } public static class MissingProvideException extends Exception { MissingProvideException(String provide) { super(provide); } } }

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> a named function: {0}."); private final AbstractCompiler compiler; private final CheckLevel checkLevel; // NOTE(nicksantos): It's a lot faster to use a shared Set that // we clear after each method call, because the Set never gets too big. private final Set<BasicBlock> blocksWithDeclarations = Sets.newHashSet(); public VariableReferenceCheck(AbstractCompiler compiler, CheckLevel checkLevel) { this.compiler = compiler; this.checkLevel = checkLevel; } @Override public void process(Node externs, Node root) { ReferenceCollectingCallback callback = new ReferenceCollectingCallback( compiler, new ReferenceCheckingBehavior()); callback.process(externs, root); } @Override public void hotSwapScript(Node scriptRoot, Node originalRoot) { ReferenceCollectingCallback callback = new ReferenceCollectingCallback( compiler, new ReferenceCheckingBehavior()); callback.hotSwapScript(scriptRoot, originalRoot); } /** * Behavior that checks variables for redeclaration or early references * just after they go out of scope. */ private class ReferenceCheckingBehavior implements Behavior { @Override public void afterExitScope(NodeTraversal t, ReferenceMap referenceMap) { // TODO(bashir) In hot-swap version this means that for global scope we // only go through all global variables accessed in the modified file not // all global variables. This should be fixed. // Check all vars after finishing a scope for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) { Var v = it.next(); checkVar(t, v, referenceMap.getReferences(v).references); } } /** * If the variable is declared more than once in a basic block, generate a * warning. Also check if a variable is used in a given scope before it is * declared, which suggest a likely error. Relies on the fact that * references is in parse-tree order. */ private void checkVar(NodeTraversal t, Var v, List<Reference> references) { blocksWithDeclarations.clear(); boolean isDeclaredInScope = false; boolean isUnhoistedNamedFunction = false; Reference hoistedFn = null; // Look for hoisted functions. for (Reference

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> reference : references) { if (reference.isHoistedFunction()) { blocksWithDeclarations.add(reference.getBasicBlock()); isDeclaredInScope = true; hoistedFn = reference; break; } else if (NodeUtil.isFunctionDeclaration( reference.getNode().getParent())) { isUnhoistedNamedFunction = true; } } for (Reference reference : references) { if (reference == hoistedFn) { continue; } BasicBlock basicBlock = reference.getBasicBlock(); boolean isDeclaration = reference.isDeclaration(); boolean allowDupe = SyntacticScopeCreator.hasDuplicateDeclarationSuppression( reference.getNode(), v); if (isDeclaration && !allowDupe) { // Look through all the declarations we've found so far, and // check if any of them are before this block. for (BasicBlock declaredBlock : blocksWithDeclarations) { if (declaredBlock.provablyExecutesBefore(basicBlock)) { // TODO(johnlenz): Fix AST generating clients that so they would // have property StaticSourceFile attached at each node. Or // better yet, make sure the generated code never violates // the requirement to pass aggressive var check! String filename = NodeUtil.getSourceName(reference.getNode()); compiler.report( JSError.make(filename, reference.getNode(), checkLevel, REDECLARED_VARIABLE, v.name)); break; } } } if (isUnhoistedNamedFunction && !isDeclaration && isDeclaredInScope) { // Only allow an unhoisted named function to be used within the // block it is declared. for (BasicBlock declaredBlock : blocksWithDeclarations) { if (!declaredBlock.provablyExecutesBefore(basicBlock)) { String filename = NodeUtil.getSourceName(reference.getNode()); compiler.report( JSError.make(filename, reference.getNode(), AMBIGUOUS_FUNCTION_DECL, v.name)); break; } } } if (!isDeclaration && !isDeclaredInScope) { // Don't check the order of refer in externs files. if (!reference.getNode().isFromExterns()) { // Special case to deal with var goog = goog || {} Node grandparent = reference

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>.getGrandparent(); if (grandparent.isName() && grandparent.getString() == v.name) { continue; } // Only generate warnings if the scopes do not match in order // to deal with possible forward declarations and recursion if (reference.getScope() == v.scope) { String filename = NodeUtil.getSourceName(reference.getNode()); compiler.report( JSError.make(filename, reference.getNode(), checkLevel, UNDECLARED_REFERENCE, v.name)); } } } if (isDeclaration) { blocksWithDeclarations.add(basicBlock); isDeclaredInScope = true; } } } } }

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>> slot = getSlot(property); if (slot == null) { return false; } return !slot.isTypeInferred(); } @Override void collectPropertyNames(Set<String> props) { for (String prop : properties.keySet()) { props.add(prop); } ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { implicitPrototype.collectPropertyNames(props); } } @Override public boolean isPropertyTypeInferred(String property) { StaticSlot<JSType> slot = getSlot(property); if (slot == null) { return false; } return slot.isTypeInferred(); } @Override public JSType getPropertyType(String property) { StaticSlot<JSType> slot = getSlot(property); if (slot == null) { return getNativeType(JSTypeNative.UNKNOWN_TYPE); } return slot.getType(); } @Override public boolean isPropertyInExterns(String propertyName) { Property p = properties.get(propertyName); if (p != null) { return p.isFromExterns(); } ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { return implicitPrototype.isPropertyInExterns(propertyName); } return false; } @Override boolean defineProperty(String name, JSType type, boolean inferred, Node propertyNode) { if (hasOwnDeclaredProperty(name)) { return false; } Property newProp = new Property( name, type, inferred, propertyNode); Property oldProp = properties.get(name); if (oldProp != null) { // This is to keep previously inferred jsdoc info, e.g., in a // replaceScript scenario. newProp.setJSDocInfo(oldProp.getJSDocInfo()); } properties.put(name, newProp); return true; } @Override public boolean removeProperty(String name) { return properties.remove(name) != null; } @Override public Node getPropertyNode(String propertyName) { Property p = properties.get(propertyName); if (p != null) { return p.getNode(); }

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>_THIS)) { options.setWarningLevel( DiagnosticGroups.GLOBAL_THIS, options.checkGlobalThisLevel); } if (options.getLanguageIn() == LanguageMode.ECMASCRIPT5_STRICT) { options.setWarningLevel( DiagnosticGroups.ES5_STRICT, CheckLevel.ERROR); } // Initialize the warnings guard. List<WarningsGuard> guards = Lists.newArrayList(); guards.add( new SuppressDocWarningsGuard( getDiagnosticGroups().getRegisteredGroups())); guards.add(options.getWarningsGuard()); ComposeWarningsGuard composedGuards = new ComposeWarningsGuard(guards); // All passes must run the variable check. This synthesizes // variables later so that the compiler doesn't crash. It also // checks the externs file for validity. If you don't want to warn // about missing variable declarations, we shut that specific // error off. if (!options.checkSymbols && !composedGuards.enables(DiagnosticGroups.CHECK_VARIABLES)) { composedGuards.addGuard(new DiagnosticGroupWarningsGuard( DiagnosticGroups.CHECK_VARIABLES, CheckLevel.OFF)); } this.warningsGuard = composedGuards; } /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSSourceFile[] inputs, CompilerOptions options) { init(Lists.<JSSourceFile>newArrayList(externs), Lists.<JSSourceFile>newArrayList(inputs), options); } /** * Initializes the instance state needed for a compile job. */ public void init(List<JSSourceFile> externs, List<JSSourceFile> inputs, CompilerOptions options) { JSModule module = new JSModule("[singleton]"); for (JSSourceFile input : inputs) { module.add(input); } initModules(externs, Lists.newArrayList(module), options); } /** * Initializes the instance state needed for a compile job if the sources * are in modules. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initModules(Lists.<JSSourceFile>newArrayList(externs), Lists

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>.<JSModule>newArrayList(modules), options); } /** * Initializes the instance state needed for a compile job if the sources * are in modules. */ public void initModules( List<JSSourceFile> externs, List<JSModule> modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); fillEmptyModules(modules); this.externs = makeCompilerInput(externs, true); // Generate the module graph, and report any errors in the module // specification as errors. this.modules = modules; if (modules.size() > 1) { try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; } } else { this.moduleGraph = null; } this.inputs = getAllInputsFromModules(modules); initBasedOnOptions(); initInputsByIdMap(); } /** * Do any initialization that is dependent on the compiler options. */ private void initBasedOnOptions() { // Create the source map if necessary. if (options.sourceMapOutputPath != null) { sourceMap = options.sourceMapFormat.getInstance(); sourceMap.setPrefixMappings(options.sourceMapLocationMappings); } } private List<CompilerInput> makeCompilerInput( List<JSSourceFile> files, boolean isExtern) { List<CompilerInput> inputs = Lists.newArrayList(); for (JSSourceFile file : files) { inputs.add(new CompilerInput(file, isExtern)); } return inputs; } private static final DiagnosticType EMPTY_MODULE_LIST_ERROR = DiagnosticType.error("JSC_EMPTY_MODULE_LIST_ERROR", "At least one module must be provided"); private static final DiagnosticType EMPTY_ROOT_MODULE_ERROR = DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(List<JSModule> modules) { if (modules.isEmpty()) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules.get(0).getInputs().isEmpty() && modules.size() > 1) { // The root module may only be empty if there is exactly 1 module. report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules.get(0).getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ private static void fillEmptyModules(List<JSModule> modules) { for (JSModule module : modules) { if (module.getInputs().isEmpty()) { module.add(JSSourceFile.fromCode("[" + module.getName() + "]", "")); } } } /** * Rebuilds the internal list of inputs by iterating over all modules. * This is necessary if inputs have been added to or removed from a module * after the {@link #init(JSSourceFile[], JSModule[], CompilerOptions)} call. */ public void rebuildInputsFromModules() { inputs = getAllInputsFromModules(modules); initInputsByIdMap(); } /** * Builds a single list of all module inputs. Verifies that it contains no * duplicates. */ private static List<CompilerInput> getAllInputsFromModules( List<JSModule> modules) { List<CompilerInput> inputs = Lists.newArrayList(); Map<String, JSModule> inputMap = Maps.newHashMap(); for (JSModule module : modules) { for (CompilerInput input : module.getInputs()) { String inputName = input.getName(); // NOTE(nicksantos): If an input is in more than one module, // it will show up twice in the inputs list, and then we // will get an error down the line. inputs.add(input); inputMap.put(inputName, module); } } return inputs; } static final DiagnosticType DUPLICATE_INPUT =

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> = new SyntheticAst(name); if (inputsById.containsKey(ast.getInputId())) { throw new IllegalArgumentException("Conflicting externs name: " + name); } CompilerInput input = new CompilerInput(ast, true); inputsById.put(input.getInputId(), input); externsRoot.addChildToFront(ast.getAstRoot(this)); externs.add(0, input); return input; } /** Add a source input dynamically. Intended for incremental compilation. */ void addIncrementalSourceAst(JsAst ast) { InputId id = ast.getInputId(); Preconditions.checkState(getInput(id) == null, "Duplicate input %s", id.getIdName()); inputsById.put(id, new CompilerInput(ast)); } /** * Replace a source input dynamically. Intended for incremental * re-compilation. * * If the new source input doesn't parse, then keep the old input * in the AST and return false. * * @return Whether the new AST was attached successfully. */ boolean replaceIncrementalSourceAst(JsAst ast) { CompilerInput oldInput = getInput(ast.getInputId()); Preconditions.checkNotNull(oldInput, "No input to replace: %s", ast.getInputId().getIdName()); Node newRoot = ast.getAstRoot(this); if (newRoot == null) { return false; } Node oldRoot = oldInput.getAstRoot(this); if (oldRoot != null) { oldRoot.getParent().replaceChild(oldRoot, newRoot); } else { getRoot().getLastChild().addChildToBack(newRoot); } CompilerInput newInput = new CompilerInput(ast); inputsById.put(ast.getInputId(), newInput); JSModule module = oldInput.getModule(); if (module != null) { module.addAfter(newInput, oldInput); module.remove(oldInput); } // Verify the input id is set properly. Preconditions.checkState( newInput.getInputId().equals(oldInput.getInputId())); InputId inputIdOnAst = newInput.getAstRoot(this).getInputId(); Preconditions.checkState(newInput.getInputId().equals(inputIdOn

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>Ast)); inputs.remove(oldInput); return true; } /** * Add a new source input dynamically. Intended for incremental compilation. * <p> * If the new source input doesn't parse, it will not be added, and a false * will be returned. * * @param ast the JS Source to add. * @return true if the source was added successfully, false otherwise. * @throws IllegalStateException if an input for this ast already exists. */ boolean addNewSourceAst(JsAst ast) { CompilerInput oldInput = getInput(ast.getInputId()); if (oldInput != null) { throw new IllegalStateException( "Input already exists: " + ast.getInputId().getIdName()); } Node newRoot = ast.getAstRoot(this); if (newRoot == null) { return false; } getRoot().getLastChild().addChildToBack(newRoot); CompilerInput newInput = new CompilerInput(ast); // TODO(tylerg): handle this for multiple modules at some point. if (moduleGraph == null && !modules.isEmpty()) { // singleton module modules.get(0).add(newInput); } inputsById.put(ast.getInputId(), newInput); return true; } @Override JSModuleGraph getModuleGraph() { return moduleGraph; } @Override public JSTypeRegistry getTypeRegistry() { if (typeRegistry == null) { typeRegistry = new JSTypeRegistry(oldErrorReporter, options.looseTypes); } return typeRegistry; } @Override MemoizedScopeCreator getTypedScopeCreator() { return getPassConfig().getTypedScopeCreator(); } @SuppressWarnings("unchecked") DefaultPassConfig ensureDefaultPassConfig() { PassConfig passes = getPassConfig().getBasePassConfig(); Preconditions.checkState(passes instanceof DefaultPassConfig, "PassConfigs must eventually delegate to the DefaultPassConfig"); return (DefaultPassConfig) passes; } public SymbolTable buildKnownSymbolTable() { SymbolTable symbolTable = new SymbolTable(getTypeRegistry()); MemoizedScopeCreator typedScopeCreator = getTypedScopeCreator(); if (typedScopeCreator != null) { symbolTable.addScopes(typedScopeCreator.getAll

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> if (hasErrors()) { return null; } } } // Check if inputs need to be rebuilt from modules. boolean staleInputs = false; for (CompilerInput input : inputs) { Node n = input.getAstRoot(this); // Inputs can have a null AST during initial parse. if (n == null) { continue; } if (n.getJSDocInfo() != null) { JSDocInfo info = n.getJSDocInfo(); if (info.isExterns()) { // If the input file is explicitly marked as an externs file, then // assume the programmer made a mistake and throw it into // the externs pile anyways. externsRoot.addChildToBack(n); input.setIsExtern(true); input.getModule().remove(input); externs.add(input); staleInputs = true; } else if (info.isNoCompile()) { input.getModule().remove(input); staleInputs = true; } } } if (staleInputs) { fillEmptyModules(modules); rebuildInputsFromModules(); } // Build the AST. for (CompilerInput input : inputs) { Node n = input.getAstRoot(this); if (n == null) { continue; } if (devMode) { runSanityCheck(); if (hasErrors()) { return null; } } if (options.sourceMapOutputPath != null || options.nameReferenceReportPath != null) { // Annotate the nodes in the tree with information from the // input file. This information is used to construct the SourceMap. SourceInformationAnnotator sia = new SourceInformationAnnotator( input.getName(), options.devMode != DevMode.OFF); NodeTraversal.traverse(this, n, sia); } jsRoot.addChildToBack(n); } if (hasErrors()) { return null; } return externAndJsRoot; } finally { stopTracer(tracer, "parseInputs"); } } /** * Transforms AMD and CJS modules to something closure compiler can * process and creates JSModules and the corresponding dependency tree * on the way

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>. */ private void processAMDAndCommonJSModules() { Map<String, JSModule> modulesByName = Maps.newLinkedHashMap(); Map<CompilerInput, JSModule> modulesByInput = Maps.newLinkedHashMap(); // TODO(nicksantos): Refactor module dependency resolution to work nicely // with multiple ways to express dependencies. Directly support JSModules // that are equivalent to a signal file and which express their deps // directly in the source. for (CompilerInput input : inputs) { input.setCompiler(this); Node root = input.getAstRoot(this); if (root == null) { continue; } if (options.transformAMDToCJSModules) { new TransformAMDToCJSModule(this).process(null, root); } if (options.processCommonJSModules) { ProcessCommonJSModules cjs = new ProcessCommonJSModules(this, options.commonJSModulePathPrefix); cjs.process(null, root); JSModule m = cjs.getModule(); if (m != null) { modulesByName.put(m.getName(), m); modulesByInput.put(input, m); } } } if (options.processCommonJSModules) { List<JSModule> modules = Lists.newArrayList(modulesByName.values()); if (!modules.isEmpty()) { this.modules = modules; this.moduleGraph = new JSModuleGraph(this.modules); } for (JSModule module : modules) { for (CompilerInput input : module.getInputs()) { for (String require : input.getRequires()) { module.addDependency(modulesByName.get(require)); } } } try { modules = Lists.newArrayList(); for (CompilerInput input : this.moduleGraph.manageDependencies( options.dependencyOptions, inputs)) { modules.add(modulesByInput.get(input)); } this.modules = modules; this.moduleGraph = new JSModuleGraph(modules); } catch (Exception e) { Throwables.propagate(e); } } } public Node parse(JSSourceFile file) { initCompilerOptionsIfTesting(); addToDebugLog("Parsing: " + file.getName()); return new

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> /** Name of the synthetic input that holds synthesized externs. */ static final String SYNTHETIC_EXTERNS = "{SyntheticVarsDeclar}"; private CompilerInput synthesizedExternsInput = null; @Override void addChangeHandler(CodeChangeHandler handler) { codeChangeHandlers.add(handler); } @Override void removeChangeHandler(CodeChangeHandler handler) { codeChangeHandlers.remove(handler); } /** * All passes should call reportCodeChange() when they alter * the JS tree structure. This is verified by CompilerTestCase. * This allows us to optimize to a fixed point. */ @Override public void reportCodeChange() { for (CodeChangeHandler handler : codeChangeHandlers) { handler.reportChange(); } } @Override public CodingConvention getCodingConvention() { CodingConvention convention = options.getCodingConvention(); convention = convention != null ? convention : defaultCodingConvention; return convention; } @Override public boolean isIdeMode() { return options.ideMode; } @Override public boolean acceptEcmaScript5() { switch (options.getLanguageIn()) { case ECMASCRIPT5: case ECMASCRIPT5_STRICT: return true; } return false; } public LanguageMode languageMode() { return options.getLanguageIn(); } @Override public boolean acceptConstKeyword() { return options.acceptConstKeyword; } @Override Config getParserConfig() { if (parserConfig == null) { Config.LanguageMode mode; switch (options.getLanguageIn()) { case ECMASCRIPT3: mode = Config.LanguageMode.ECMASCRIPT3; break; case ECMASCRIPT5: mode = Config.LanguageMode.ECMASCRIPT5; break; case ECMASCRIPT5_STRICT: mode = Config.LanguageMode.ECMASCRIPT5_STRICT; break; default: throw new IllegalStateException("unexpected language mode"); } parserConfig = ParserRunner.createConfig( isIdeMode(), mode, acceptConstKeyword(), options.extraAnnotationNames); } return parserConfig; } @Override public boolean isTypeChecking

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>Name, int lineno, int charno) { super(registry, registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE)); Preconditions.checkNotNull(reference); this.reference = reference; this.sourceName = sourceName; this.lineno = lineno; this.charno = charno; } @Override boolean defineProperty(String propertyName, JSType type, boolean inferred, Node propertyNode) { if (!isResolved()) { // If this is an unresolved object type, we need to save all its // properties and define them when it is resolved. if (propertyContinuations == null) { propertyContinuations = Lists.newArrayList(); } propertyContinuations.add( new PropertyContinuation( propertyName, type, inferred, propertyNode)); return true; } else { return super.defineProperty( propertyName, type, inferred, propertyNode); } } private void finishPropertyContinuations() { ObjectType referencedObjType = getReferencedObjTypeInternal(); if (referencedObjType != null && !referencedObjType.isUnknownType()) { if (propertyContinuations != null) { for (PropertyContinuation c : propertyContinuations) { c.commit(this); } } } propertyContinuations = null; } /** Returns the type to which this refers (which is unknown if unresolved). */ public JSType getReferencedType() { return getReferencedTypeInternal(); } @Override public String getReferenceName() { return reference; } @Override public String toString() { return reference; } @Override public boolean hasReferenceName() { return true; } @Override boolean isNamedType() { return true; } @Override public boolean isNominalType() { return true; } /** * Two named types are equivalent if they are the same {@code * ObjectType} object. This is complicated by the fact that isEquivalent * is sometimes called before we have a chance to resolve the type * names. * * @return {@code true} iff {@code that} == {@code this} or {@code that} * is a {@link NamedType} whose reference is the same as ours, * or {@code that} is the type we reference. */

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> node, we want to grab the list // of nodes that this node affects. List<DiGraphNode<N, Branch>> nextNodes = isForward() ? cfg.getDirectedSuccNodes(curNode) : cfg.getDirectedPredNodes(curNode); for (DiGraphNode<N, Branch> nextNode : nextNodes) { if (nextNode != cfg.getImplicitReturn()) { orderedWorkSet.add(nextNode); } } } step++; } if (isForward()) { joinInputs(getCfg().getImplicitReturn()); } } /** * Gets the state of the initial estimation at each node. * * @return Initial state. */ abstract L createInitialEstimateLattice(); /** * Gets the incoming state of the entry node. * * @return Entry state. */ abstract L createEntryLattice(); /** * Initializes the work list and the control flow graph. */ protected void initialize() { // TODO(user): Calling clear doesn't deallocate the memory in a // LinkedHashSet. Consider creating a new work set if we plan to repeatedly // call analyze. orderedWorkSet.clear(); for (DiGraphNode<N, Branch> node : cfg.getDirectedGraphNodes()) { node.setAnnotation(new FlowState<L>(createInitialEstimateLattice(), createInitialEstimateLattice())); if (node != cfg.getImplicitReturn()) { orderedWorkSet.add(node); } } } /** * Performs a single flow through a node. * * @return {@code true} if the flow state differs from the previous state. */ protected boolean flow(DiGraphNode<N, Branch> node) { FlowState<L> state = node.getAnnotation(); if (isForward()) { L outBefore = state.out; state.out = flowThrough(node.getValue(), state.in); return !outBefore.equals(state.out); } else { L inBefore = state.in; state.in = flowThrough(node.getValue(), state.out); return !inBefore.equals(state.in); } } /** * Computes the new flow state at a given node's entry by

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> merging the * output (input) lattice of the node's predecessor (successor). * * @param node Node to compute new join. */ protected void joinInputs(DiGraphNode<N, Branch> node) { FlowState<L> state = node.getAnnotation(); if (isForward()) { if (cfg.getEntry() == node) { state.setIn(createEntryLattice()); } else { List<DiGraphNode<N, Branch>> inNodes = cfg.getDirectedPredNodes(node); if (inNodes.size() == 1) { FlowState<L> inNodeState = inNodes.get(0).getAnnotation(); state.setIn(inNodeState.getOut()); } else if (inNodes.size() > 1) { List<L> values = new ArrayList<L>(inNodes.size()); for (DiGraphNode<N, Branch> currentNode : inNodes) { FlowState<L> currentNodeState = currentNode.getAnnotation(); values.add(currentNodeState.getOut()); } state.setIn(joinOp.apply(values)); } } } else { List<DiGraphNode<N, Branch>> inNodes = cfg.getDirectedSuccNodes(node); if (inNodes.size() == 1) { DiGraphNode<N, Branch> inNode = inNodes.get(0); if (inNode == cfg.getImplicitReturn()) { state.setOut(createEntryLattice()); } else { FlowState<L> inNodeState = inNode.getAnnotation(); state.setOut(inNodeState.getIn()); } } else if (inNodes.size() > 1) { List<L> values = new ArrayList<L>(inNodes.size()); for (DiGraphNode<N, Branch> currentNode : inNodes) { FlowState<L> currentNodeState = currentNode.getAnnotation(); values.add(currentNodeState.getIn()); } state.setOut(joinOp.apply(values)); } } } /** * The in and out states of a node. * * @param <L> Input and output lattice element type. */ static class FlowState<L extends Lattice

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>Element> implements Annotation { private L in; private L out; /** * Private constructor. No other classes should create new states. * * @param inState Input. * @param outState Output. */ private FlowState(L inState, L outState) { Preconditions.checkNotNull(inState); Preconditions.checkNotNull(outState); this.in = inState; this.out = outState; } L getIn() { return in; } void setIn(L in) { Preconditions.checkNotNull(in); this.in = in; } L getOut() { return out; } void setOut(L out) { Preconditions.checkNotNull(out); this.out = out; } @Override public String toString() { return String.format("IN: %s OUT: %s", in, out); } @Override public int hashCode() { return Objects.hashCode(in, out); } } /** * The exception to be thrown if the analysis has been running for a long * number of iterations. Chances are the analysis is not monotonic, a * fixed-point cannot be found and it is currently stuck in an infinite loop. */ static class MaxIterationsExceededException extends RuntimeException { private static final long serialVersionUID = 1L; MaxIterationsExceededException(String msg) { super(msg); } } abstract static class BranchedForwardDataFlowAnalysis <N, L extends LatticeElement> extends DataFlowAnalysis<N, L> { @Override protected void initialize() { orderedWorkSet.clear(); for (DiGraphNode<N, Branch> node : getCfg().getDirectedGraphNodes()) { int outEdgeCount = getCfg().getOutEdges(node.getValue()).size(); List<L> outLattices = Lists.newArrayList(); for (int i = 0; i < outEdgeCount; i++) { outLattices.add(createInitialEstimateLattice()); } node.setAnnotation(new BranchedFlowState<L>( createInitialEstimateLattice(), outLattices)); if (node != getCfg().getImplicitReturn()) { orderedWorkSet.add(node); }

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>FlowState<L> predNodeState = predNode.getAnnotation(); L in = predNodeState.out.get( getCfg().getDirectedSuccNodes(predNode).indexOf(node)); values.add(in); } if (getCfg().getEntry() == node) { state.setIn(createEntryLattice()); } else if (!values.isEmpty()) { state.setIn(joinOp.apply(values)); } } } /** * The in and out states of a node. * * @param <L> Input and output lattice element type. */ static class BranchedFlowState<L extends LatticeElement> implements Annotation { private L in; private List<L> out; /** * Private constructor. No other classes should create new states. * * @param inState Input. * @param outState Output. */ private BranchedFlowState(L inState, List<L> outState) { Preconditions.checkNotNull(inState); Preconditions.checkNotNull(outState); this.in = inState; this.out = outState; } L getIn() { return in; } void setIn(L in) { Preconditions.checkNotNull(in); this.in = in; } List<L> getOut() { return out; } void setOut(List<L> out) { Preconditions.checkNotNull(out); for (L item : out) { Preconditions.checkNotNull(item); } this.out = out; } @Override public String toString() { return String.format("IN: %s OUT: %s", in, out); } @Override public int hashCode() { return Objects.hashCode(in, out); } } /** * Compute set of escaped variables. When a variable is escaped in a * dataflow analysis, it can be reference outside of the code that we are * analyzing. A variable is escaped if any of the following is true: * * <p><ol> * <li>It is defined as the exception name in CATCH clause so it became a * variable local not to our definition of scope.</li> * <li>Exported variables as they

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> can be needed after the script terminates. * </li> * <li>Names of named functions because in javascript, <i>function foo(){}</i> * does not kill <i>foo</i> in the dataflow.</li> */ static void computeEscaped(final Scope jsScope, final Set<Var> escaped, AbstractCompiler compiler) { // TODO(user): Very good place to store this information somewhere. AbstractPostOrderCallback finder = new AbstractPostOrderCallback() { @Override public void visit(NodeTraversal t, Node n, Node parent) { if (jsScope == t.getScope() || !n.isName() || parent.isFunction()) { return; } String name = n.getString(); Var var = t.getScope().getVar(name); if (var != null && var.scope == jsScope) { escaped.add(jsScope.getVar(name)); } } }; NodeTraversal t = new NodeTraversal(compiler, finder); t.traverseAtScope(jsScope); // 1: Remove the exception name in CATCH which technically isn't local to // begin with. for (Iterator<Var> i = jsScope.getVars(); i.hasNext();) { Var var = i.next(); if (var.getParentNode().isCatch() || compiler.getCodingConvention().isExported(var.getName())) { escaped.add(var); } } } }

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS><String> getters = Sets.newHashSet(); Set<String> setters = Sets.newHashSet(); for (Node key = n.getFirstChild(); key != null; key = key.getNext()) { if (!noCajaChecks && key.getString().endsWith("__")) { t.report(key, ILLEGAL_NAME); } if (!key.isSetterDef()) { // normal property and getter cases if (getters.contains(key.getString())) { t.report(key, DUPLICATE_OBJECT_KEY); } else { getters.add(key.getString()); } } if (!key.isGetterDef()) { // normal property and setter cases if (setters.contains(key.getString())) { t.report(key, DUPLICATE_OBJECT_KEY); } else { setters.add(key.getString()); } } } } /** Checks that label names are valid. */ private void checkLabel(NodeTraversal t, Node n) { if (n.getFirstChild().getString().endsWith("__")) { if (!noCajaChecks) { t.report(n.getFirstChild(), ILLEGAL_NAME); } } } /** Checks that are performed on non-extern code only. */ private class NonExternChecks extends AbstractPostOrderCallback { @Override public void visit(NodeTraversal t, Node n, Node parent) { if ((n.isName()) && isDeclaration(n)) { checkDeclaration(t, n); } else if (n.isGetProp()) { checkProperty(t, n); } } /** Checks for illegal declarations. */ private void checkDeclaration(NodeTraversal t, Node n) { if ("eval".equals(n.getString())) { t.report(n, EVAL_DECLARATION); } else if ("arguments".equals(n.getString())) { t.report(n, ARGUMENTS_DECLARATION); } else if (n.getString().endsWith("__")) { if (!noCajaChecks) { t.report(n, ILLEGAL_NAME); } } } /** Checks for illegal property accesses. */ private void checkProperty(NodeTraversal t, Node n

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>Set; /** * An enum type representing a branded collection of elements. Each element * is referenced by its name, and has an {@link EnumElementType} type. */ public class EnumType extends PrototypeObjectType { private static final long serialVersionUID = 1L; /** * The object literal or alias which this type represents. * It may be {@code null}. */ private final Node source; // the type of the individual elements private EnumElementType elementsType; // the elements' names (they all have the same type) private final Set<String> elements = new HashSet<String>(); /** * Creates an enum type. * * @param name the enum's name * @param elementsType the base type of the individual elements */ EnumType(JSTypeRegistry registry, String name, Node source, JSType elementsType) { super(registry, "enum{" + name + "}", null); this.source = source; this.elementsType = new EnumElementType(registry, elementsType, name); } /** * Gets the source node or null if this is an unknown enum. */ public Node getSource() { return source; } @Override public EnumType toMaybeEnumType() { return this; } @Override public ObjectType getImplicitPrototype() { return registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE); } /** * Gets the elements defined on this enum. * @return the elements' names defined on this enum. The returned set is * immutable. */ public Set<String> getElements() { return Collections.unmodifiableSet(elements); } /** * Defines a new element on this enum. * @param name the name of the new element * @param definingNode the {@code Node} that defines this new element * @return true iff the new element is added successfully */ public boolean defineElement(String name, Node definingNode) { elements.add(name); return defineDeclaredProperty(name, elementsType, definingNode); } /** * Gets the elements' type. */ public EnumElementType getElementsType() { return elementsType; } @Override public TernaryValue testForEquality(JSType that) { TernaryValue result

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> name <arg2> * -- block * | * --return * | * --add * |-- string foo * -- name <arg1> * </pre> * * @param builder the message builder * @param node the function node that contains a message * @throws MalformedException if the parsed message is invalid */ private void extractFromFunctionNode(Builder builder, Node node) throws MalformedException { Set<String> phNames = Sets.newHashSet(); for (Node fnChild : node.children()) { switch (fnChild.getType()) { case Token.NAME: // This is okay. The function has a name, but it is empty. break; case Token.PARAM_LIST: // Parse the placeholder names from the function argument list. for (Node argumentNode : fnChild.children()) { if (argumentNode.isName()) { String phName = argumentNode.getString(); if (phNames.contains(phName)) { throw new MalformedException("Duplicate placeholder name: " + phName, argumentNode); } else { phNames.add(phName); } } } break; case Token.BLOCK: // Build the message's value by examining the return statement Node returnNode = fnChild.getFirstChild(); if (!returnNode.isReturn()) { throw new MalformedException("RETURN node expected; found: " + getReadableTokenName(returnNode), returnNode); } for (Node child : returnNode.children()) { extractFromReturnDescendant(builder, child); } // Check that all placeholders from the message text have appropriate // object literal keys for (String phName : builder.getPlaceholders()) { if(!phNames.contains(phName)) { throw new MalformedException( "Unrecognized message placeholder referenced: " + phName, returnNode); } } break; default: throw new MalformedException( "NAME, LP, or BLOCK node expected; found: " + getReadableTokenName(node), fnChild); } } } /** * Appends value parts to the message builder by traversing the descendants * of the given RETURN node.

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>(); if (stringLiteralNode == null) { throw new MalformedException("Message string literal expected", stringLiteralNode); } // Parse the message string and append parts to the builder parseMessageTextNode(builder, stringLiteralNode); Node objLitNode = stringLiteralNode.getNext(); Set<String> phNames = Sets.newHashSet(); if (objLitNode != null) { // Register the placeholder names if (!objLitNode.isObjectLit()) { throw new MalformedException("OBJLIT node expected", objLitNode); } for (Node aNode = objLitNode.getFirstChild(); aNode != null; aNode = aNode.getNext()) { if (!aNode.isString()) { throw new MalformedException("STRING node expected as OBJLIT key", aNode); } String phName = aNode.getString(); if (!isLowerCamelCaseWithNumericSuffixes(phName)) { throw new MalformedException( "Placeholder name not in lowerCamelCase: " + phName, aNode); } if (phNames.contains(phName)) { throw new MalformedException("Duplicate placeholder name: " + phName, aNode); } phNames.add(phName); } } // Check that all placeholders from the message text have appropriate objlit // values Set<String> usedPlaceholders = builder.getPlaceholders(); for (String phName : usedPlaceholders) { if(!phNames.contains(phName)) { throw new MalformedException( "Unrecognized message placeholder referenced: " + phName, objLitNode); } } // Check that objLiteral have only names that are present in the // message text for (String phName : phNames) { if(!usedPlaceholders.contains(phName)) { throw new MalformedException( "Unused message placeholder: " + phName, objLitNode); } } } /** * Appends the message parts in a JS message value extracted from the given * text node. * * @param builder the js message builder to append parts to * @param node the node with string literal that contains the message text * @throws MalformedException if {@code value} contains a reference to

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>; if any of these * properties is invalidated it causes an error. */ private final Map<String, CheckLevel> propertiesToErrorFor; private class Property { /** The name of the property. */ final String name; /** All types on which the field exists, grouped together if related. */ private UnionFind<T> types; /** * A set of types for which renaming this field should be skipped. This * list is first filled by fields defined in the externs file. */ Set<T> typesToSkip = Sets.newHashSet(); /** * If true, do not rename any instance of this field, as it has been * referenced from an unknown type. */ boolean skipRenaming; /** Set of nodes for this field that need renaming. */ Set<Node> renameNodes = Sets.newHashSet(); /** * Map from node to the highest type in the prototype chain containing the * field for that node. In the case of a union, the type is the highest type * of one of the types in the union. */ final Map<Node, T> rootTypes = Maps.newHashMap(); Property(String name) { this.name = name; } /** Returns the types on which this field is referenced. */ UnionFind<T> getTypes() { if (types == null) { types = new StandardUnionFind<T>(); } return types; } /** * Record that this property is referenced from this type. * @return true if the type was recorded for this property, else false, * which would happen if the type was invalidating. */ boolean addType(T type, T top, T relatedType) { checkState(!skipRenaming, "Attempt to record skipped property: %s", name); if (typeSystem.isInvalidatingType(top)) { invalidate(); return false; } else { if (typeSystem.isTypeToSkip(top)) { addTypeToSkip(top); } if (relatedType == null) { getTypes().add(top); } else { getTypes().union(top, relatedType); } typeSystem.recordInterfaces(type, top, this); return true; } } /** Records the

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> given type as one to skip for this property. */ void addTypeToSkip(T type) { for (T skipType : typeSystem.getTypesToSkipForType(type)) { typesToSkip.add(skipType); getTypes().union(skipType, type); } } /** Invalidates any types related to invalid types. */ void expandTypesToSkip() { // If we are not going to rename any properties, then we do not need to // update the list of invalid types, as they are all invalid. if (shouldRename()) { int count = 0; while (true) { // It should usually only take one time through this do-while. checkState(++count < 10, "Stuck in loop expanding types to skip."); // Make sure that the representative type for each type to skip is // marked as being skipped. Set<T> rootTypesToSkip = Sets.newHashSet(); for (T subType : typesToSkip) { rootTypesToSkip.add(types.find(subType)); } typesToSkip.addAll(rootTypesToSkip); Set<T> newTypesToSkip = Sets.newHashSet(); Set<T> allTypes = types.elements(); int originalTypesSize = allTypes.size(); for (T subType : allTypes) { if (!typesToSkip.contains(subType) && typesToSkip.contains(types.find(subType))) { newTypesToSkip.add(subType); } } for (T newType : newTypesToSkip) { addTypeToSkip(newType); } // If there were not any new types added, we are done here. if (types.elements().size() == originalTypesSize) { break; } } } } /** Returns true if any instance of this property should be renamed. */ boolean shouldRename() { return !skipRenaming && types != null && types.allEquivalenceClasses().size() > 1; } /** * Returns true if this property should be renamed on this type. * expandTypesToSkip() should be called before this, if anything has been * added to the typesToSkip list. */ boolean shouldRename(

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>T type) { return !skipRenaming && !typesToSkip.contains(type); } /** * Invalidates a field from renaming. Used for field references on an * object with unknown type. */ boolean invalidate() { boolean changed = !skipRenaming; skipRenaming = true; types = null; return changed; } /** * Schedule the node to potentially be renamed. * @param node the node to rename * @param type the highest type in the prototype chain for which the * property is defined * @return True if type was accepted without invalidation or if the property * was already invalidated. False if this property was invalidated this * time. */ boolean scheduleRenaming(Node node, T type) { if (!skipRenaming) { if (typeSystem.isInvalidatingType(type)) { invalidate(); return false; } renameNodes.add(node); rootTypes.put(node, type); } return true; } } private Map<String, Property> properties = Maps.newHashMap(); static DisambiguateProperties<JSType> forJSTypeSystem( AbstractCompiler compiler, Map<String, CheckLevel> propertiesToErrorFor) { return new DisambiguateProperties<JSType>( compiler, new JSTypeSystem(compiler), propertiesToErrorFor); } static DisambiguateProperties<ConcreteType> forConcreteTypeSystem( AbstractCompiler compiler, TightenTypes tt, Map<String, CheckLevel> propertiesToErrorFor) { return new DisambiguateProperties<ConcreteType>( compiler, new ConcreteTypeSystem(tt, compiler.getCodingConvention()), propertiesToErrorFor); } /** * This constructor should only be called by one of the helper functions * above for either the JSType system, or the concrete type system. */ private DisambiguateProperties(AbstractCompiler compiler, TypeSystem<T> typeSystem, Map<String, CheckLevel> propertiesToErrorFor) { this.compiler = compiler; this.typeSystem = typeSystem; this.propertiesToErrorFor = propertiesToErrorFor; if (!this.propertiesToErrorFor.isEmpty()) { this.invalidationMap =

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>. */ T getTypeWithProperty(String field, T type) { return typeSystem.getTypeWithProperty(field, type); } /** Tracks the current type system scope while traversing. */ private abstract class AbstractScopingCallback implements ScopedCallback { protected final Stack<StaticScope<T>> scopes = new Stack<StaticScope<T>>(); @Override public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) { return true; } @Override public void enterScope(NodeTraversal t) { if (t.inGlobalScope()) { scopes.push(typeSystem.getRootScope()); } else { scopes.push(typeSystem.getFunctionScope(t.getScopeRoot())); } } @Override public void exitScope(NodeTraversal t) { scopes.pop(); } /** Returns the current scope at this point in the file. */ protected StaticScope<T> getScope() { return scopes.peek(); } } /** * Finds all properties defined in the externs file and sets them as * ineligible for renaming from the type on which they are defined. */ private class FindExternProperties extends AbstractScopingCallback { @Override public void visit(NodeTraversal t, Node n, Node parent) { // TODO(johnlenz): Support object-literal property definitions. if (n.isGetProp()) { String field = n.getLastChild().getString(); T type = typeSystem.getType(getScope(), n.getFirstChild(), field); Property prop = getProperty(field); if (typeSystem.isInvalidatingType(type)) { prop.invalidate(); } else { prop.addTypeToSkip(type); // If this is a prototype property, then we want to skip assignments // to the instance type as well. These assignments are not usually // seen in the extern code itself, so we must handle them here. if ((type = typeSystem.getInstanceFromPrototype(type)) != null) { prop.getTypes().add(type); prop.typesToSkip.add(type); } } } } } /** * Traverses the tree, building a map from field names to Nodes for all * fields that can be renamed.

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>.newHashSet( registry.getNativeType(JSTypeNative.ALL_TYPE), registry.getNativeType(JSTypeNative.NO_OBJECT_TYPE), registry.getNativeType(JSTypeNative.NO_TYPE), registry.getNativeType(JSTypeNative.FUNCTION_PROTOTYPE), registry.getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE), registry.getNativeType(JSTypeNative.OBJECT_PROTOTYPE), registry.getNativeType(JSTypeNative.TOP_LEVEL_PROTOTYPE), registry.getNativeType(JSTypeNative.UNKNOWN_TYPE)); } @Override public void addInvalidatingType(JSType type) { checkState(!type.isUnionType()); invalidatingTypes.add(type); } @Override public StaticScope<JSType> getRootScope() { return null; } @Override public StaticScope<JSType> getFunctionScope(Node node) { return null; } @Override public JSType getType( StaticScope<JSType> scope, Node node, String prop) { if (node.getJSType() == null) { return registry.getNativeType(JSTypeNative.UNKNOWN_TYPE); } return node.getJSType(); } @Override public boolean isInvalidatingType(JSType type) { if (type == null || invalidatingTypes.contains(type) || type.isUnknownType() /* unresolved types */) { return true; } ObjectType objType = ObjectType.cast(type); return objType != null && !objType.hasReferenceName(); } @Override public ImmutableSet<JSType> getTypesToSkipForType(JSType type) { type = type.restrictByNotNullOrUndefined(); if (type.isUnionType()) { Set<JSType> types = Sets.newHashSet(type); for (JSType alt : type.toMaybeUnionType().getAlternates()) { types.addAll(getTypesToSkipForTypeNonUnion(type)); } return ImmutableSet.copyOf(types); } else if (type.isEnumElementType()) { return getTypesToSkipForType( type.toMaybeEnumElementType().getPrimitiveType()); } return ImmutableSet.copyOf(getTypesToSkipForTypeNon

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>Union(type)); } private Set<JSType> getTypesToSkipForTypeNonUnion(JSType type) { Set<JSType> types = Sets.newHashSet(); JSType skipType = type; while (skipType != null) { types.add(skipType); ObjectType objSkipType = skipType.toObjectType(); if (objSkipType != null) { skipType = objSkipType.getImplicitPrototype(); } else { break; } } return types; } @Override public boolean isTypeToSkip(JSType type) { return type.isEnumType() || (type.autoboxesTo() != null); } @Override public JSType restrictByNotNullOrUndefined(JSType type) { return type.restrictByNotNullOrUndefined(); } @Override public Iterable<JSType> getTypeAlternatives(JSType type) { if (type.isUnionType()) { return type.toMaybeUnionType().getAlternates(); } else { ObjectType objType = type.toObjectType(); if (objType != null && objType.getConstructor() != null && objType.getConstructor().isInterface()) { List<JSType> list = Lists.newArrayList(); for (FunctionType impl : registry.getDirectImplementors(objType)) { list.add(impl.getInstanceType()); } return list; } else { return null; } } } @Override public ObjectType getTypeWithProperty(String field, JSType type) { if (type == null) { return null; } if (type.isEnumElementType()) { return getTypeWithProperty( field, type.toMaybeEnumElementType().getPrimitiveType()); } if (!(type instanceof ObjectType)) { if (type.autoboxesTo() != null) { type = type.autoboxesTo(); } else { return null; } } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> top = getTypeWithProperty(p.name, itype); if (top != null) { p.addType(itype, top, relatedType); } else { recordInterfaces(itype, relatedType, p); } // If this interface invalidated this property, return now. if (p.skipRenaming) return; } if (constructor.isInterface() || constructor.isConstructor()) { constructor = constructor.getSuperClassConstructor(); } else { constructor = null; } } } } } /** Implementation of TypeSystem using concrete types. */ private static class ConcreteTypeSystem implements TypeSystem<ConcreteType> { private final TightenTypes tt; private int nextUniqueId; private CodingConvention codingConvention; private final Set<JSType> invalidatingTypes = Sets.newHashSet(); // An array of native types that are not tracked by type tightening, and // thus need to be added in if an unknown type is encountered. private static final JSTypeNative [] nativeTypes = new JSTypeNative[] { JSTypeNative.BOOLEAN_OBJECT_TYPE, JSTypeNative.NUMBER_OBJECT_TYPE, JSTypeNative.STRING_OBJECT_TYPE }; public ConcreteTypeSystem(TightenTypes tt, CodingConvention convention) { this.tt = tt; this.codingConvention = convention; } @Override public void addInvalidatingType(JSType type) { checkState(!type.isUnionType()); invalidatingTypes.add(type); } @Override public StaticScope<ConcreteType> getRootScope() { return tt.getTopScope(); } @Override public StaticScope<ConcreteType> getFunctionScope(Node decl) { ConcreteFunctionType func = tt.getConcreteFunction(decl); return (func != null) ? func.getScope() : (StaticScope<ConcreteType>) null; } @Override public ConcreteType getType( StaticScope<ConcreteType> scope, Node node, String prop) { if (scope != null) { ConcreteType c = tt.inferConcreteType( (TightenTypes.ConcreteScope) scope, node); return maybeAddAutoboxes(c, node, prop); } else { return null; } } /**

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>.idGeneratorMap; } GlobalNamespace getGlobalNamespace() { return namespaceForChecks; } PreprocessorSymbolTable getPreprocessorSymbolTable() { return preprocessorSymbolTable; } void maybeInitializePreprocessorSymbolTable(AbstractCompiler compiler) { if (options.ideMode) { Node root = compiler.getRoot(); if (preprocessorSymbolTable == null || preprocessorSymbolTable.getRootNode() != root) { preprocessorSymbolTable = new PreprocessorSymbolTable(root); } } } @Override protected List<PassFactory> getChecks() { List<PassFactory> checks = Lists.newArrayList(); if (options.closurePass) { checks.add(closureGoogScopeAliases); } if (options.nameAnonymousFunctionsOnly) { if (options.anonymousFunctionNaming == AnonymousFunctionNamingPolicy.MAPPED) { checks.add(nameMappedAnonymousFunctions); } else if (options.anonymousFunctionNaming == AnonymousFunctionNamingPolicy.UNMAPPED) { checks.add(nameUnmappedAnonymousFunctions); } return checks; } checks.add(checkSideEffects); if (options.checkSuspiciousCode || options.enables(DiagnosticGroups.GLOBAL_THIS) || options.enables(DiagnosticGroups.DEBUGGER_STATEMENT_PRESENT)) { checks.add(suspiciousCode); } if (options.checkControlStructures || options.enables(DiagnosticGroups.ES5_STRICT)) { checks.add(checkControlStructures); } if (options.checkRequires.isOn()) { checks.add(checkRequires); } if (options.checkProvides.isOn()) { checks.add(checkProvides); } // The following passes are more like "preprocessor" passes. // It's important that they run before most checking passes. // Perhaps this method should be renamed? if (options.generateExports) { checks.add(generateExports); } if (options.exportTestFunctions) { checks.add(exportTestFunctions); } if (options.closurePass) { checks.add(closurePrimitives.makeOneTimePass()); } if (options.jqueryPass) { checks.add(jqueryAliases.makeOneTime

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>Pass()); } if (options.closurePass && options.checkMissingGetCssNameLevel.isOn()) { checks.add(closureCheckGetCssName); } if (options.syntheticBlockStartMarker != null) { // This pass must run before the first fold constants pass. checks.add(createSyntheticBlocks); } checks.add(checkVars); if (options.computeFunctionSideEffects) { checks.add(checkRegExp); } if (options.aggressiveVarCheck.isOn()) { checks.add(checkVariableReferences); } // This pass should run before types are assigned. if (options.processObjectPropertyString) { checks.add(objectPropertyStringPreprocess); } if (options.checkTypes || options.inferTypes) { checks.add(resolveTypes.makeOneTimePass()); checks.add(inferTypes.makeOneTimePass()); if (options.checkTypes) { checks.add(checkTypes.makeOneTimePass()); } else { checks.add(inferJsDocInfo.makeOneTimePass()); } } if (options.checkUnreachableCode.isOn() || (options.checkTypes && options.checkMissingReturn.isOn())) { checks.add(checkControlFlow); } // CheckAccessControls only works if check types is on. if (options.checkTypes && (options.enables(DiagnosticGroups.ACCESS_CONTROLS) || options.enables(DiagnosticGroups.CONSTANT_PROPERTY))) { checks.add(checkAccessControls); } if (options.checkGlobalNamesLevel.isOn()) { checks.add(checkGlobalNames); } if (options.enables(DiagnosticGroups.ES5_STRICT) || options.checkCaja) { checks.add(checkStrictMode); } // Replace 'goog.getCssName' before processing defines but after the // other checks have been done. if (options.closurePass) { checks.add(closureReplaceGetCssName); } // i18n // If you want to customize the compiler to use a different i18n pass, // you can create a PassConfig that calls replacePassFactory // to replace this. checks.add(

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>options.messageBundle != null ? replaceMessages : createEmptyPass("replaceMessages")); if (options.getTweakProcessing().isOn()) { checks.add(processTweaks); } // Defines in code always need to be processed. checks.add(processDefines); if (options.instrumentationTemplate != null || options.recordFunctionInformation) { checks.add(computeFunctionNames); } if (options.nameReferenceGraphPath != null && !options.nameReferenceGraphPath.isEmpty()) { checks.add(printNameReferenceGraph); } if (options.nameReferenceReportPath != null && !options.nameReferenceReportPath.isEmpty()) { checks.add(printNameReferenceReport); } assertAllOneTimePasses(checks); return checks; } @Override protected List<PassFactory> getOptimizations() { List<PassFactory> passes = Lists.newArrayList(); passes.add(garbageCollectChecks); // TODO(nicksantos): The order of these passes makes no sense, and needs // to be re-arranged. if (options.runtimeTypeCheck) { passes.add(runtimeTypeCheck); } passes.add(createEmptyPass("beforeStandardOptimizations")); if (options.replaceIdGenerators) { passes.add(replaceIdGenerators); } // Optimizes references to the arguments variable. if (options.optimizeArgumentsArray) { passes.add(optimizeArgumentsArray); } // Abstract method removal works best on minimally modified code, and also // only needs to run once. if (options.closurePass && (options.removeAbstractMethods || options.removeClosureAsserts)) { passes.add(closureCodeRemoval); } // Collapsing properties can undo constant inlining, so we do this before // the main optimization loop. if (options.collapseProperties) { passes.add(collapseProperties); } // ReplaceStrings runs after CollapseProperties in order to simplify // pulling in values of constants defined in enums structures. if (!options.replaceStringsFunctionDescriptions.isEmpty()) { passes.add(replaceStrings); } // Tighten types based on actual usage. if (options.tightenTypes) { passes.add(tightenTypes

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>Builder); } // Property disambiguation should only run once and needs to be done // soon after type checking, both so that it can make use of type // information and so that other passes can take advantage of the renamed // properties. if (options.disambiguateProperties) { passes.add(disambiguateProperties); } if (options.computeFunctionSideEffects) { passes.add(markPureFunctions); } else if (options.markNoSideEffectCalls) { // TODO(user) The properties that this pass adds to CALL and NEW // AST nodes increase the AST's in-memory size. Given that we are // already running close to our memory limits, we could run into // trouble if we end up using the @nosideeffects annotation a lot // or compute @nosideeffects annotations by looking at function // bodies. It should be easy to propagate @nosideeffects // annotations as part of passes that depend on this property and // store the result outside the AST (which would allow garbage // collection once the pass is done). passes.add(markNoSideEffectCalls); } if (options.chainCalls) { passes.add(chainCalls); } // Constant checking must be done after property collapsing because // property collapsing can introduce new constants (e.g. enum values). if (options.inlineConstantVars) { passes.add(checkConsts); } // The Caja library adds properties to Object.prototype, which breaks // most for-in loops. This adds a check to each loop that skips // any property matching /___$/. if (options.ignoreCajaProperties) { passes.add(ignoreCajaProperties); } assertAllOneTimePasses(passes); if (options.smartNameRemoval || options.reportPath != null) { passes.addAll(getCodeRemovingPasses()); passes.add(smartNamePass); } // This needs to come after the inline constants pass, which is run within // the code removing passes. if (options.closurePass) { passes.add(closureOptimizePrimitives); } // TODO(user): This forces a first crack at crossModuleCodeMotion // before devirtualization. Once certain functions are de

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>virtualized, // it confuses crossModuleCodeMotion ability to recognized that // it is recursive. // TODO(user): This is meant for a temporary quick win. // In the future, we might want to improve our analysis in // CrossModuleCodeMotion so we don't need to do this. if (options.crossModuleCodeMotion) { passes.add(crossModuleCodeMotion); } // Method devirtualization benefits from property disambiguiation so // it should run after that pass but before passes that do // optimizations based on global names (like cross module code motion // and inline functions). Smart Name Removal does better if run before // this pass. if (options.devirtualizePrototypeMethods) { passes.add(devirtualizePrototypeMethods); } if (options.customPasses != null) { passes.add(getCustomPasses( CustomPassExecutionTime.BEFORE_OPTIMIZATION_LOOP)); } passes.add(createEmptyPass("beforeMainOptimizations")); if (options.specializeInitialModule) { // When specializing the initial module, we want our fixups to be // as lean as possible, so we run the entire optimization loop to a // fixed point before specializing, then specialize, and then run the // main optimization loop again. passes.addAll(getMainOptimizationLoop()); if (options.crossModuleCodeMotion) { passes.add(crossModuleCodeMotion); } if (options.crossModuleMethodMotion) { passes.add(crossModuleMethodMotion); } passes.add(specializeInitialModule.makeOneTimePass()); } passes.addAll(getMainOptimizationLoop()); passes.add(createEmptyPass("beforeModuleMotion")); if (options.crossModuleCodeMotion) { passes.add(crossModuleCodeMotion); } if (options.crossModuleMethodMotion) { passes.add(crossModuleMethodMotion); } passes.add(createEmptyPass("afterModuleMotion")); // Some optimizations belong outside the loop because running them more // than once would either have no benefit or be incorrect. if (options.customPasses != null) { passes.add(getCustomPasses( CustomPassExecutionTime.AFTER_OPTIMIZATION_LOOP

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>)); } if (options.flowSensitiveInlineVariables) { passes.add(flowSensitiveInlineVariables); // After inlining some of the variable uses, some variables are unused. // Re-run remove unused vars to clean it up. if (options.removeUnusedVars) { passes.add(removeUnusedVars); } } // Running this pass again is required to have goog.events compile down to // nothing when compiled on its own. if (options.smartNameRemoval) { passes.add(smartNamePass2); } if (options.collapseAnonymousFunctions) { passes.add(collapseAnonymousFunctions); } // Move functions before extracting prototype member declarations. if (options.moveFunctionDeclarations || // renamePrefixNamescape relies on moveFunctionDeclarations // to preserve semantics. options.renamePrefixNamespace != null) { passes.add(moveFunctionDeclarations); } if (options.anonymousFunctionNaming == AnonymousFunctionNamingPolicy.MAPPED) { passes.add(nameMappedAnonymousFunctions); } // The mapped name anonymous function pass makes use of information that // the extract prototype member declarations pass removes so the former // happens before the latter. // // Extracting prototype properties screws up the heuristic renaming // policies, so never run it when those policies are requested. if (options.extractPrototypeMemberDeclarations && (options.propertyRenaming != PropertyRenamingPolicy.HEURISTIC && options.propertyRenaming != PropertyRenamingPolicy.AGGRESSIVE_HEURISTIC)) { passes.add(extractPrototypeMemberDeclarations); } if (options.ambiguateProperties && (options.propertyRenaming == PropertyRenamingPolicy.ALL_UNQUOTED)) { passes.add(ambiguateProperties); } if (options.propertyRenaming != PropertyRenamingPolicy.OFF) { passes.add(renameProperties); } // Reserve global names added to the "windows" object. if (options.reserveRawExports) { passes.add(gatherRawExports); } // This comes after property renaming because quoted property names must // not be renamed. if (options.convertToDottedProperties) { passes.add(convertToDottedProperties); } // Property renaming must happen before this pass

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> runs since this // pass may convert dotted properties into quoted properties. It // is beneficial to run before alias strings, alias keywords and // variable renaming. if (options.rewriteFunctionExpressions) { passes.add(rewriteFunctionExpressions); } // This comes after converting quoted property accesses to dotted property // accesses in order to avoid aliasing property names. if (!options.aliasableStrings.isEmpty() || options.aliasAllStrings) { passes.add(aliasStrings); } if (options.aliasExternals) { passes.add(aliasExternals); } if (options.aliasKeywords) { passes.add(aliasKeywords); } // Passes after this point can no longer depend on normalized AST // assumptions. passes.add(markUnnormalized); if (options.coalesceVariableNames) { passes.add(coalesceVariableNames); // coalesceVariables creates identity assignments and more redundant code // that can be removed, rerun the peephole optimizations to clean them // up. if (options.foldConstants) { passes.add(peepholeOptimizations); } } if (options.collapseVariableDeclarations) { passes.add(exploitAssign); passes.add(collapseVariableDeclarations); } // This pass works best after collapseVariableDeclarations. passes.add(denormalize); if (options.instrumentationTemplate != null) { passes.add(instrumentFunctions); } if (options.variableRenaming != VariableRenamingPolicy.ALL) { // If we're leaving some (or all) variables with their old names, // then we need to undo any of the markers we added for distinguishing // local variables ("$$1"). passes.add(invertContextualRenaming); } if (options.variableRenaming != VariableRenamingPolicy.OFF) { passes.add(renameVars); } if (options.groupVariableDeclarations) { passes.add(groupVariableDeclarations); } // This pass should run after names stop changing. if (options.processObjectPropertyString) { passes.add(objectPropertyStringPostprocess); } if (options.labelRenaming) { passes.add(renameLabels); } if (options.foldConstants)

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> { passes.add(latePeepholeOptimizations); } if (options.anonymousFunctionNaming == AnonymousFunctionNamingPolicy.UNMAPPED) { passes.add(nameUnmappedAnonymousFunctions); } if (options.renamePrefixNamespace != null) { if (!GLOBAL_SYMBOL_NAMESPACE_PATTERN.matcher( options.renamePrefixNamespace).matches()) { throw new IllegalArgumentException( "Illegal character in renamePrefixNamespace name: " + options.renamePrefixNamespace); } passes.add(rescopeGlobalSymbols); } passes.add(stripSideEffectProtection); // Safety checks passes.add(sanityCheckAst); passes.add(sanityCheckVars); return passes; } /** Creates the passes for the main optimization loop. */ private List<PassFactory> getMainOptimizationLoop() { List<PassFactory> passes = Lists.newArrayList(); if (options.inlineGetters) { passes.add(inlineSimpleMethods); } passes.addAll(getCodeRemovingPasses()); if (options.inlineFunctions || options.inlineLocalFunctions) { passes.add(inlineFunctions); } boolean runOptimizeCalls = options.optimizeCalls || options.optimizeParameters || options.optimizeReturns; if (options.removeUnusedVars || options.removeUnusedLocalVars) { if (options.deadAssignmentElimination) { passes.add(deadAssignmentsElimination); } if (!runOptimizeCalls) { passes.add(removeUnusedVars); } } if (runOptimizeCalls) { passes.add(optimizeCallsAndRemoveUnusedVars); } assertAllLoopablePasses(passes); return passes; } /** Creates several passes aimed at removing code. */ private List<PassFactory> getCodeRemovingPasses() { List<PassFactory> passes = Lists.newArrayList(); if (options.collapseObjectLiterals && !isInliningForbidden()) { passes.add(collapseObjectLiterals); } if (options.inlineVariables || options.inlineLocalVariables) { passes.add(inlineVariables); } else if (options.inlineConstantVars) { passes.add(inlineConstants); } if (options.foldConstants) { // These used to be one pass.

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> passes.add(minimizeExitPoints); passes.add(peepholeOptimizations); } if (options.removeDeadCode) { passes.add(removeUnreachableCode); } if (options.removeUnusedPrototypeProperties) { passes.add(removeUnusedPrototypeProperties); passes.add(removeUnusedClassProperties); } assertAllLoopablePasses(passes); return passes; } /** * Checks for code that is probably wrong (such as stray expressions). */ final HotSwapPassFactory checkSideEffects = new HotSwapPassFactory("checkSideEffects", true) { @Override protected HotSwapCompilerPass createInternal(final AbstractCompiler compiler) { // The current approach to protecting "hidden" side-effects is to // wrap them in a function call that is stripped later, this shouldn't // be done in IDE mode where AST changes may be unexpected. boolean protectHiddenSideEffects = options.protectHiddenSideEffects && !options.ideMode; return new CheckSideEffects(compiler, options.checkSuspiciousCode ? CheckLevel.WARNING : CheckLevel.OFF, protectHiddenSideEffects); } }; /** * Checks for code that is probably wrong (such as stray expressions). */ final PassFactory stripSideEffectProtection = new PassFactory("stripSideEffectProtection", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new CheckSideEffects.StripProtection(compiler); } }; /** * Checks for code that is probably wrong (such as stray expressions). */ // TODO(bolinfest): Write a CompilerPass for this. final HotSwapPassFactory suspiciousCode = new HotSwapPassFactory("suspiciousCode", true) { @Override protected HotSwapCompilerPass createInternal(final AbstractCompiler compiler) { List<Callback> sharedCallbacks = Lists.newArrayList(); if (options.checkSuspiciousCode) { sharedCallbacks.add(new CheckAccidentalSemicolon(CheckLevel.WARNING)); } if (options.enables(DiagnosticGroups.GLOBAL_THIS)) { sharedCallbacks.add(new CheckGlobalThis(compiler)); } if (options.enables(DiagnosticGroups.DEBUGGER_STATEMENT_

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>PRESENT)) { sharedCallbacks.add(new CheckDebuggerStatement(compiler)); } return combineChecks(compiler, sharedCallbacks); } }; /** Verify that all the passes are one-time passes. */ private void assertAllOneTimePasses(List<PassFactory> passes) { for (PassFactory pass : passes) { Preconditions.checkState(pass.isOneTimePass()); } } /** Verify that all the passes are multi-run passes. */ private void assertAllLoopablePasses(List<PassFactory> passes) { for (PassFactory pass : passes) { Preconditions.checkState(!pass.isOneTimePass()); } } /** Checks for validity of the control structures. */ final HotSwapPassFactory checkControlStructures = new HotSwapPassFactory("checkControlStructures", true) { @Override protected HotSwapCompilerPass createInternal(AbstractCompiler compiler) { return new ControlStructureCheck(compiler); } }; /** Checks that all constructed classes are goog.require()d. */ final HotSwapPassFactory checkRequires = new HotSwapPassFactory("checkRequires", true) { @Override protected HotSwapCompilerPass createInternal(AbstractCompiler compiler) { return new CheckRequiresForConstructors(compiler, options.checkRequires); } }; /** Makes sure @constructor is paired with goog.provides(). */ final HotSwapPassFactory checkProvides = new HotSwapPassFactory("checkProvides", true) { @Override protected HotSwapCompilerPass createInternal(AbstractCompiler compiler) { return new CheckProvides(compiler, options.checkProvides); } }; private static final DiagnosticType GENERATE_EXPORTS_ERROR = DiagnosticType.error( "JSC_GENERATE_EXPORTS_ERROR", "Exports can only be generated if export symbol/property " + "functions are set."); /** Generates exports for @export annotations. */ final PassFactory generateExports = new PassFactory("generateExports", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { CodingConvention convention = compiler.getCodingConvention(); if (convention.getExportSymbolFunction() != null && convention.getExportPropertyFunction() != null) { return new GenerateExports(compiler, convention.getExportSymbolFunction(),

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>SwapCompilerPass() { @Override public void process(Node externs, Node root) { Preconditions.checkNotNull(topScope); Preconditions.checkNotNull(getTypedScopeCreator()); makeInferJsDocInfo(compiler).process(externs, root); } @Override public void hotSwapScript(Node scriptRoot, Node originalRoot) { makeInferJsDocInfo(compiler).hotSwapScript(scriptRoot, originalRoot); } }; } }; /** Checks type usage */ final HotSwapPassFactory checkTypes = new HotSwapPassFactory("checkTypes", false) { @Override protected HotSwapCompilerPass createInternal(final AbstractCompiler compiler) { return new HotSwapCompilerPass() { @Override public void process(Node externs, Node root) { Preconditions.checkNotNull(topScope); Preconditions.checkNotNull(getTypedScopeCreator()); TypeCheck check = makeTypeCheck(compiler); check.process(externs, root); compiler.getErrorManager().setTypedPercent(check.getTypedPercent()); } @Override public void hotSwapScript(Node scriptRoot, Node originalRoot) { makeTypeCheck(compiler).check(scriptRoot, false); } }; } }; /** * Checks possible execution paths of the program for problems: missing return * statements and dead code. */ final HotSwapPassFactory checkControlFlow = new HotSwapPassFactory("checkControlFlow", true) { @Override protected HotSwapCompilerPass createInternal(AbstractCompiler compiler) { List<Callback> callbacks = Lists.newArrayList(); if (options.checkUnreachableCode.isOn()) { callbacks.add( new CheckUnreachableCode(compiler, options.checkUnreachableCode)); } if (options.checkMissingReturn.isOn() && options.checkTypes) { callbacks.add( new CheckMissingReturn(compiler, options.checkMissingReturn)); } return combineChecks(compiler, callbacks); } }; /** Checks access controls. Depends on type-inference. */ final HotSwapPassFactory checkAccessControls = new HotSwapPassFactory("checkAccessControls", true) { @Override protected HotSwapCompilerPass createInternal(AbstractCompiler compiler) { return new CheckAccessControls(compiler); } };

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>Restricted = new UnionTypeBuilder(registry); UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry); for (JSType element : alternates) { TypePair p = element.getTypesUnderShallowInequality(that); if (p.typeA != null) { thisRestricted.addAlternate(p.typeA); } if (p.typeB != null) { thatRestricted.addAlternate(p.typeB); } } return new TypePair( thisRestricted.build(), thatRestricted.build()); } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseUnionType(this); } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { setResolvedTypeInternal(this); // for circularly defined types. boolean changed = false; ImmutableList.Builder<JSType> resolvedTypes = ImmutableList.builder(); for (JSType alternate : alternates) { JSType newAlternate = alternate.resolve(t, scope); changed |= (alternate != newAlternate); resolvedTypes.add(alternate); } if (changed) { Collection<JSType> newAlternates = resolvedTypes.build(); Preconditions.checkState( newAlternates.hashCode() == this.hashcode); alternates = newAlternates; } return this; } @Override public String toDebugHashCodeString() { List<String> hashCodes = Lists.newArrayList(); for (JSType a : alternates) { hashCodes.add(a.toDebugHashCodeString()); } return "{(" + Joiner.on(",").join(hashCodes) + ")}"; } @Override public boolean setValidator(Predicate<JSType> validator) { for (JSType a : alternates) { a.setValidator(validator); } return true; } @Override public JSType collapseUnion() { JSType currentValue = null; ObjectType currentCommonSuper = null; for (JSType a : alternates) { if (a.isUnknownType()) { return getNativeType(JSTypeNative.UNKNOWN_TYPE); } ObjectType obj = a.toObjectType(); if (obj == null) {

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>(); continue retry; case EXTERNS: if (!jsdocBuilder.recordExterns()) { parser.addParserWarning("msg.jsdoc.externs", stream.getLineno(), stream.getCharno()); } token = eatTokensUntilEOL(); continue retry; case JAVA_DISPATCH: if (!jsdocBuilder.recordJavaDispatch()) { parser.addParserWarning("msg.jsdoc.javadispatch", stream.getLineno(), stream.getCharno()); } token = eatTokensUntilEOL(); continue retry; case EXTENDS: case IMPLEMENTS: skipEOLs(); token = next(); lineno = stream.getLineno(); charno = stream.getCharno(); boolean matchingRc = false; if (token == JsDocToken.LC) { token = next(); matchingRc = true; } if (token == JsDocToken.STRING) { Node typeNode = parseAndRecordTypeNameNode( token, lineno, charno, matchingRc); lineno = stream.getLineno(); charno = stream.getCharno(); typeNode = wrapNode(Token.BANG, typeNode); if (typeNode != null && !matchingRc) { typeNode.putBooleanProp(Node.BRACELESS_TYPE, true); } type = createJSTypeExpression(typeNode); if (annotation == Annotation.EXTENDS) { // record the extended type, check later extendedTypes.add(new ExtendedTypeInfo( type, stream.getLineno(), stream.getCharno())); } else { Preconditions.checkState( annotation == Annotation.IMPLEMENTS); if (!jsdocBuilder.recordImplementedInterface(type)) { parser.addTypeWarning("msg.jsdoc.implements.duplicate", lineno, charno); } } token = next(); if (matchingRc) { if (token != JsDocToken.RC) { parser.addTypeWarning("msg.jsdoc.missing.rc", stream.getLineno(), stream.getCharno()); } } else if (token != JsDocToken.EOL && token != JsDocToken.EOF && token != JsDocToken.EOC) { parser.addTypeWarning("

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> Set<String> suppressions = new HashSet<String>(); while (true) { if (match(JsDocToken.STRING)) { String name = stream.getString(); if (!suppressionNames.contains(name)) { parser.addParserWarning("msg.jsdoc.suppress.unknown", name, stream.getLineno(), stream.getCharno()); } suppressions.add(stream.getString()); token = next(); } else { parser.addParserWarning("msg.jsdoc.suppress", stream.getLineno(), stream.getCharno()); return token; } if (match(JsDocToken.PIPE)) { token = next(); } else { break; } } if (!match(JsDocToken.RC)) { parser.addParserWarning("msg.jsdoc.suppress", stream.getLineno(), stream.getCharno()); } else { token = next(); if (!jsdocBuilder.recordSuppressions(suppressions)) { parser.addParserWarning("msg.jsdoc.suppress.duplicate", stream.getLineno(), stream.getCharno()); } } } return token; } /** * Parse a {@code @modifies} tag of the form * {@code @modifies&#123;this|arguments|param&#125;}. * * @param token The current token. */ private JsDocToken parseModifiesTag(JsDocToken token) { if (token == JsDocToken.LC) { Set<String> modifies = new HashSet<String>(); while (true) { if (match(JsDocToken.STRING)) { String name = stream.getString(); if (!modifiesAnnotationKeywords.contains(name) && !jsdocBuilder.hasParameter(name)) { parser.addParserWarning("msg.jsdoc.modifies.unknown", name, stream.getLineno(), stream.getCharno()); } modifies.add(stream.getString()); token = next(); } else { parser.addParserWarning("msg.jsdoc.modifies", stream.getLineno(), stream.getCharno()); return token; } if (match(JsDocToken.PIPE))

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>Annotations()}. Edges' annotation values are cleared. */ public final void pushEdgeAnnotations() { if (edgeAnnotationStack == null) { edgeAnnotationStack = Lists.newLinkedList(); } pushAnnotations(edgeAnnotationStack, getEdges()); } /** * Restores edges' annotation values to state before last * {@link #pushEdgeAnnotations()}. */ public final void popEdgeAnnotations() { Preconditions.checkNotNull(edgeAnnotationStack, "Popping edge annotations without pushing."); popAnnotations(edgeAnnotationStack); } /** * A generic edge. * * @param <N> Value type that the graph node stores. * @param <E> Value type that the graph edge stores. */ public interface GraphEdge<N, E> extends Annotatable { /** * Retrieves the edge's value. * * @return The value. */ E getValue(); GraphNode<N, E> getNodeA(); GraphNode<N, E> getNodeB(); } /** * A simple implementation of SubGraph that calculates adjacency by iterating * over a node's neighbors. */ class SimpleSubGraph<N, E> implements SubGraph<N, E> { private Graph<N, E> graph; private List<GraphNode<N, E>> nodes = Lists.newArrayList(); SimpleSubGraph(Graph<N, E> graph) { this.graph = graph; } @Override public boolean isIndependentOf(N value) { GraphNode<N, E> node = graph.getNode(value); for (GraphNode<N, E> n : nodes) { if (graph.getNeighborNodes(n.getValue()).contains(node)) { return false; } } return true; } @Override public void addNode(N value) { nodes.add(graph.getNodeOrFail(value)); } } /** * Pushes a new list on stack and stores nodes annotations in the new list. * Clears objects' annotations as well. */ private static void pushAnnotations( Deque<GraphAnnotationState> stack, Collection<? extends Annotatable> haveAnnotations) { stack.push(new GraphAnnotationState(haveAnnotations.size())); for (Annotatable h : haveAnnotations

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>) { stack.peek().add(new AnnotationState(h, h.getAnnotation())); h.setAnnotation(null); } } /** * Restores the node annotations on the top of stack and pops stack. */ private static void popAnnotations(Deque<GraphAnnotationState> stack) { for (AnnotationState as : stack.pop()) { as.first.setAnnotation(as.second); } } }

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>.setSourceFile(file); } /** Returns the SourceAst object on which this input is based. */ public SourceAst getSourceAst() { return ast; } /** Sets an error manager for routing error messages. */ public void setErrorManager(ErrorManager errorManager) { this.errorManager = errorManager; } /** Sets an abstract compiler for doing parsing. */ public void setCompiler(AbstractCompiler compiler) { this.compiler = compiler; setErrorManager(compiler.getErrorManager()); } /** Gets a list of types depended on by this input. */ @Override public Collection<String> getRequires() { Preconditions.checkNotNull(errorManager, "Expected setErrorManager to be called first"); try { regenerateDependencyInfoIfNecessary(); return Collections.<String>unmodifiableSet(requires); } catch (IOException e) { errorManager.report(CheckLevel.ERROR, JSError.make(AbstractCompiler.READ_ERROR, getName())); return ImmutableList.<String>of(); } } /** Gets a list of types provided by this input. */ @Override public Collection<String> getProvides() { Preconditions.checkNotNull(errorManager, "Expected setErrorManager to be called first"); try { regenerateDependencyInfoIfNecessary(); return Collections.<String>unmodifiableSet(provides); } catch (IOException e) { errorManager.report(CheckLevel.ERROR, JSError.make(AbstractCompiler.READ_ERROR, getName())); return ImmutableList.<String>of(); } } // TODO(nicksantos): Remove addProvide/addRequire/removeRequire once // there is better support for discovering non-closure dependencies. void addProvide(String provide) { getProvides(); provides.add(provide); } void addRequire(String require) { getRequires(); requires.add(require); } public void removeRequire(String require) { getRequires(); requires.remove(require); } /** * Regenerates the provides/requires if we need to do so. */ private void regenerateDependencyInfoIfNecessary() throws IOException { // If the code is NOT a JsAst, then it was not originally JS code. // Look at the Ast for dependency info. if (!(ast instanceof

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> JsAst)) { Preconditions.checkNotNull(compiler, "Expected setCompiler to be called first"); DepsFinder finder = new DepsFinder(); Node root = getAstRoot(compiler); if (root == null) { return; } finder.visitTree(getAstRoot(compiler)); // TODO(nicksantos|user): This caching behavior is a bit // odd, and only works if you assume the exact call flow that // clients are currently using. In that flow, they call // getProvides(), then remove the goog.provide calls from the // AST, and then call getProvides() again. // // This won't work for any other call flow, or any sort of incremental // compilation scheme. The API needs to be fixed so callers aren't // doing weird things like this, and then we should get rid of the // multiple-scan strategy. provides.addAll(finder.provides); requires.addAll(finder.requires); } else { // Otherwise, look at the source code. if (!generatedDependencyInfoFromSource) { // Note: it's ok to use getName() instead of // getPathRelativeToClosureBase() here because we're not using // this to generate deps files. (We're only using it for // symbol dependencies.) DependencyInfo info = (new JsFileParser(errorManager)).parseFile( getName(), getName(), getCode()); provides.addAll(info.getProvides()); requires.addAll(info.getRequires()); generatedDependencyInfoFromSource = true; } } } private static class DepsFinder { private final List<String> provides = Lists.newArrayList(); private final List<String> requires = Lists.newArrayList(); private final CodingConvention codingConvention = new ClosureCodingConvention(); void visitTree(Node n) { visitSubtree(n, null); } void visitSubtree(Node n, Node parent) { if (n.isCall()) { String require = codingConvention.extractClassNameIfRequire(n, parent); if (require != null) { requires.add(require); } String provide = codingConvention.extractClassNameIfProvide(n, parent); if (provide != null) { provides.add(provide); } return; }

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>(); } /** * @return Whether the node is used as a statement. */ static boolean isStatement(Node n) { return isStatementParent(n.getParent()); } static boolean isStatementParent(Node parent) { // It is not possible to determine definitely if a node is a statement // or not if it is not part of the AST. A FUNCTION node can be // either part of an expression or a statement. Preconditions.checkState(parent != null); switch (parent.getType()) { case Token.SCRIPT: case Token.BLOCK: case Token.LABEL: return true; default: return false; } } /** Whether the node is part of a switch statement. */ static boolean isSwitchCase(Node n) { return n.isCase() || n.isDefaultCase(); } /** * @return Whether the name is a reference to a variable, function or * function parameter (not a label or a empty function expression name). */ static boolean isReferenceName(Node n) { return n.isName() && !n.getString().isEmpty(); } /** Whether the child node is the FINALLY block of a try. */ static boolean isTryFinallyNode(Node parent, Node child) { return parent.isTry() && parent.getChildCount() == 3 && child == parent.getLastChild(); } /** Whether the node is a CATCH container BLOCK. */ static boolean isTryCatchNodeContainer(Node n) { Node parent = n.getParent(); return parent.isTry() && parent.getFirstChild().getNext() == n; } /** Safely remove children while maintaining a valid node structure. */ static void removeChild(Node parent, Node node) { if (isTryFinallyNode(parent, node)) { if (NodeUtil.hasCatchHandler(getCatchBlock(parent))) { // A finally can only be removed if there is a catch. parent.removeChild(node); } else { // Otherwise only its children can be removed. node.detachChildren(); } } else if (node.isCatch()) { // The CATCH can can only be removed if there is a finally clause. Node tryNode = node.getParent().getParent(); Preconditions.checkState

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> the block was removed. */ static boolean tryMergeBlock(Node block) { Preconditions.checkState(block.isBlock()); Node parent = block.getParent(); // Try to remove the block if its parent is a block/script or if its // parent is label and it has exactly one child. if (isStatementBlock(parent)) { Node previous = block; while (block.hasChildren()) { Node child = block.removeFirstChild(); parent.addChildAfter(child, previous); previous = child; } parent.removeChild(block); return true; } else { return false; } } /** * @param node A node * @return Whether the call is a NEW or CALL node. */ static boolean isCallOrNew(Node node) { return node.isCall() || node.isNew(); } /** * Return a BLOCK node for the given FUNCTION node. */ static Node getFunctionBody(Node fn) { Preconditions.checkArgument(fn.isFunction()); return fn.getLastChild(); } /** * Is this node or any of its children a CALL? */ static boolean containsCall(Node n) { return containsType(n, Token.CALL); } /** * Is this node a function declaration? A function declaration is a function * that has a name that is added to the current scope (i.e. a function that * is not part of a expression; see {@link #isFunctionExpression}). */ static boolean isFunctionDeclaration(Node n) { return n.isFunction() && isStatement(n); } /** * Is this node a hoisted function declaration? A function declaration in the * scope root is hoisted to the top of the scope. * See {@link #isFunctionDeclaration}). */ static boolean isHoistedFunctionDeclaration(Node n) { return isFunctionDeclaration(n) && (n.getParent().isScript() || n.getParent().getParent().isFunction()); } /** * Is a FUNCTION node an function expression? An function expression is one * that has either no name or a name that is not added to the current scope. * * <p>Some examples of function expressions: * <pre> * (function () {}) * (

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>function f() {})() * [ function f() {} ] * var f = function f() {}; * for (function f() {};;) {} * </pre> * * <p>Some examples of functions that are <em>not</em> expressions: * <pre> * function f() {} * if (x); else function f() {} * for (;;) { function f() {} } * </pre> * * @param n A node * @return Whether n is an function used within an expression. */ static boolean isFunctionExpression(Node n) { return n.isFunction() && !isStatement(n); } /** * Determines if a node is a function expression that has an empty body. * * @param node a node * @return whether the given node is a function expression that is empty */ static boolean isEmptyFunctionExpression(Node node) { return isFunctionExpression(node) && isEmptyBlock(node.getLastChild()); } /** * Determines if a function takes a variable number of arguments by * looking for references to the "arguments" var_args object. */ static boolean isVarArgsFunction(Node function) { Preconditions.checkArgument(function.isFunction()); return isNameReferenced( function.getLastChild(), "arguments", MATCH_NOT_FUNCTION); } /** * @return Whether node is a call to methodName. * a.f(...) * a['f'](...) */ static boolean isObjectCallMethod(Node callNode, String methodName) { if (callNode.isCall()) { Node functionIndentifyingExpression = callNode.getFirstChild(); if (isGet(functionIndentifyingExpression)) { Node last = functionIndentifyingExpression.getLastChild(); if (last != null && last.isString()) { String propName = last.getString(); return (propName.equals(methodName)); } } } return false; } /** * @return Whether the callNode represents an expression in the form of: * x.call(...) * x['call'](...) */ static boolean isFunctionObjectCall(Node callNode) { return isObjectCallMethod(callNode, "call"); } /** * @return Whether the call

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> them are duplicates of // one another. int currentIndex = 0; Iterator<JSType> it = alternates.iterator(); while (it.hasNext()) { JSType current = it.next(); // Unknown and NoResolved types may just be names that haven't // been resolved yet. So keep these in the union, and just use // equality checking for simple de-duping. if (alternate.isUnknownType() || current.isUnknownType() || alternate.isNoResolvedType() || current.isNoResolvedType()) { if (alternate.isEquivalentTo(current)) { // Alternate is unnecessary. return this; } } else { if (alternate.isSubtype(current)) { // Alternate is unnecessary. return this; } else if (current.isSubtype(alternate)) { // Alternate makes current obsolete it.remove(); if (currentIndex == functionTypePosition) { functionTypePosition = -1; } else if (currentIndex < functionTypePosition) { functionTypePosition--; currentIndex--; } } } currentIndex++; } if (alternate.isFunctionType()) { // See the comments on functionTypePosition above. Preconditions.checkState(functionTypePosition == -1); functionTypePosition = alternates.size(); } alternates.add(alternate); result = null; // invalidate the memoized result } } else { result = null; } return this; } /** * Reduce the alternates into a non-union type. * If the alternates can't be accurately represented with a non-union * type, return null. */ private JSType reduceAlternatesWithoutUnion() { if (isAllType) { return registry.getNativeType(ALL_TYPE); } else if (isNativeUnknownType) { if (areAllUnknownsChecked) { return registry.getNativeType(CHECKED_UNKNOWN_TYPE); } else { return registry.getNativeType(UNKNOWN_TYPE); } } else { int size = alternates.size(); if (size > maxUnionSize) { return registry.getNativeType(UNKNOWN_TYPE); } else if (size > 1) { return null; } else

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> void visit(NodeTraversal t, Node n, Node parent) { if (!n.isCall()) { return; } String callName = n.getFirstChild().getQualifiedName(); TweakFunction tweakFunc = TWEAK_FUNCTIONS_MAP.get(callName); if (tweakFunc == null) { return; } if (tweakFunc == TweakFunction.GET_COMPILER_OVERRIDES) { getOverridesCalls.add( new TweakFunctionCall(t.getSourceName(), tweakFunc, n)); return; } // Ensure the first parameter (the tweak ID) is a string literal. Node tweakIdNode = n.getFirstChild().getNext(); if (!tweakIdNode.isString()) { compiler.report(t.makeError(tweakIdNode, NON_LITERAL_TWEAK_ID_ERROR)); return; } String tweakId = tweakIdNode.getString(); // Make sure there is a TweakInfo structure for it. TweakInfo tweakInfo = allTweaks.get(tweakId); if (tweakInfo == null) { tweakInfo = new TweakInfo(tweakId); allTweaks.put(tweakId, tweakInfo); } switch (tweakFunc) { case REGISTER_BOOLEAN: case REGISTER_NUMBER: case REGISTER_STRING: // Ensure the ID contains only valid characters. if (!ID_MATCHER.matchesAllOf(tweakId)) { compiler.report(t.makeError(tweakIdNode, INVALID_TWEAK_ID_ERROR)); } // Ensure tweaks are registered in the global scope. if (!t.inGlobalScope()) { compiler.report( t.makeError(n, NON_GLOBAL_TWEAK_INIT_ERROR, tweakId)); break; } // Ensure tweaks are registered only once. if (tweakInfo.isRegistered()) { compiler.report( t.makeError(n, TWEAK_MULTIPLY_REGISTERED_ERROR, tweakId)); break; } Node tweakDefaultValueNode = tweakIdNode.getNext().getNext(); tweakInfo.addRegisterCall(t.getSourceName(), tweakFunc, n, tweakDefaultValueNode); break; case OVERRIDE_DEFAULT_VALUE

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>AllTypeWarnings(); } else { emitUnknownTweakErrors(); } } /** * Emits a warning for each default value parameter that has the wrong type * and for each getter function that was used for the wrong type of tweak. */ void emitAllTypeWarnings() { for (TweakFunctionCall call : functionCalls) { Node valueNode = call.valueNode; TweakFunction tweakFunc = call.tweakFunc; TweakFunction registerFunc = registerCall.tweakFunc; if (valueNode != null) { // For register* and overrideDefaultValue calls, ensure the default // value is a literal of the correct type. if (!registerFunc.isValidNodeType(valueNode.getType())) { compiler.report(JSError.make(call.sourceName, valueNode, INVALID_TWEAK_DEFAULT_VALUE_WARNING, tweakId, registerFunc.getName(), registerFunc.getExpectedTypeName())); } } else if (tweakFunc.isGetterFunction()) { // For getter calls, ensure the correct getter was used. if (!tweakFunc.isCorrectRegisterFunction(registerFunc)) { compiler.report(JSError.make(call.sourceName, call.callNode, TWEAK_WRONG_GETTER_TYPE_WARNING, tweakFunc.getName(), registerFunc.getName())); } } } } /** * Emits an error for each function call that was found. */ void emitUnknownTweakErrors() { for (TweakFunctionCall call : functionCalls) { compiler.report(JSError.make(call.sourceName, call.getIdNode(), UNKNOWN_TWEAK_WARNING, tweakId)); } } void addRegisterCall(String sourceName, TweakFunction tweakFunc, Node callNode, Node defaultValueNode) { registerCall = new TweakFunctionCall(sourceName, tweakFunc, callNode, defaultValueNode); functionCalls.add(registerCall); } void addOverrideDefaultValueCall(String sourceName, TweakFunction tweakFunc, Node callNode, Node defaultValueNode) { functionCalls.add(new TweakFunctionCall(sourceName, tweakFunc, callNode, defaultValueNode)); this.defaultValueNode = defaultValueNode; } void addGetterCall(

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>String sourceName, TweakFunction tweakFunc, Node callNode) { functionCalls.add(new TweakFunctionCall(sourceName, tweakFunc, callNode)); } boolean isRegistered() { return registerCall != null; } Node getDefaultValueNode() { Preconditions.checkState(isRegistered()); // Use calls to goog.tweak.overrideDefaultValue() first. if (defaultValueNode != null) { return defaultValueNode; } // Use the value passed to the register function next. if (registerCall.valueNode != null) { return registerCall.valueNode; } // Otherwise, use the default value for the tweak's type. return registerCall.tweakFunc.createDefaultValueNode(); } } }

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> (currentParam.getNext() != null && newParam.isVarArgs()) { newParam.setVarArgs(false); newParam.setOptionalArg(true); } } else { warnedAboutArgList |= addParameter( paramBuilder, typeRegistry.getNativeType(UNKNOWN_TYPE), warnedAboutArgList, codingConvention.isOptionalParameter(currentParam) || oldParamsListHitOptArgs, codingConvention.isVarArgsParameter(currentParam)); } } parametersNode = paramBuilder.build(); } return this; } /** * Infer the return type from JSDocInfo. */ FunctionTypeBuilder inferReturnType(@Nullable JSDocInfo info) { if (info != null && info.hasReturnType()) { returnType = info.getReturnType().evaluate(scope, typeRegistry); returnTypeInferred = false; } if (templateTypeName != null && returnType != null && returnType.restrictByNotNullOrUndefined().isTemplateType()) { reportError(TEMPLATE_TYPE_EXPECTED, fnName); } return this; } /** * Infer the role of the function (whether it's a constructor or interface) * and what it inherits from in JSDocInfo. */ FunctionTypeBuilder inferInheritance(@Nullable JSDocInfo info) { if (info != null) { isConstructor = info.isConstructor(); isInterface = info.isInterface(); // base type if (info.hasBaseType()) { if (isConstructor) { JSType maybeBaseType = info.getBaseType().evaluate(scope, typeRegistry); if (maybeBaseType != null && maybeBaseType.setValidator(new ExtendedTypeValidator())) { baseType = (ObjectType) maybeBaseType; } } else { reportWarning(EXTENDS_WITHOUT_TYPEDEF, fnName); } } // implemented interfaces if (isConstructor || isInterface) { implementedInterfaces = Lists.newArrayList(); for (JSTypeExpression t : info.getImplementedInterfaces()) { JSType maybeInterType = t.evaluate(scope, typeRegistry); if (maybeInterType != null && maybeInterType.setValidator(new ImplementedTypeValidator())) { implementedInterfaces.add((ObjectType) maybeInterType); }

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> } } else if (info.getImplementedInterfaceCount() > 0) { reportWarning(IMPLEMENTS_WITHOUT_CONSTRUCTOR, fnName); } // extended interfaces (for interface only) if (isInterface) { extendedInterfaces = Lists.newArrayList(); for (JSTypeExpression t : info.getExtendedInterfaces()) { JSType maybeInterfaceType = t.evaluate(scope, typeRegistry); if (maybeInterfaceType != null && maybeInterfaceType.setValidator(new ExtendedTypeValidator())) { extendedInterfaces.add((ObjectType) maybeInterfaceType); } } } } return this; } /** * Infers the type of {@code this}. * @param type The type of this if the info is missing. */ FunctionTypeBuilder inferThisType(JSDocInfo info, JSType type) { // Look at the @this annotation first. inferThisType(info); if (thisType == null) { ObjectType objType = ObjectType.cast(type); if (objType != null && (info == null || !info.hasType())) { thisType = objType; } } return this; } /** * Infers the type of {@code this}. * @param info The JSDocInfo for this function. */ FunctionTypeBuilder inferThisType(JSDocInfo info) { ObjectType maybeThisType = null; if (info != null && info.hasThisType()) { maybeThisType = ObjectType.cast( info.getThisType().evaluate(scope, typeRegistry)); } if (maybeThisType != null) { thisType = maybeThisType; thisType.setValidator(new ThisTypeValidator()); } return this; } /** * Infer the parameter types from the doc info alone. */ FunctionTypeBuilder inferParameterTypes(JSDocInfo info) { // Create a fake args parent. Node lp = IR.paramList(); for (String name : info.getParameterNames()) { lp.addChildToBack(IR.name(name)); } return inferParameterTypes(lp, info); } /** * Infer the parameter types from the list of argument names and * the doc info. */ FunctionTypeBuilder inferParameter

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> true; } } } return false; } } /** Holds data dynamically inferred about functions. */ static interface FunctionContents { /** Returns the source node of this function. May be null. */ Node getSourceNode(); /** Returns if the function may be in externs. */ boolean mayBeFromExterns(); /** Returns if a return of a real value (not undefined) appears. */ boolean mayHaveNonEmptyReturns(); /** Gets a list of variables in this scope that are escaped. */ Iterable<String> getEscapedVarNames(); } static class UnknownFunctionContents implements FunctionContents { private static UnknownFunctionContents singleton = new UnknownFunctionContents(); static FunctionContents get() { return singleton; } @Override public Node getSourceNode() { return null; } @Override public boolean mayBeFromExterns() { return true; } @Override public boolean mayHaveNonEmptyReturns() { return true; } @Override public Iterable<String> getEscapedVarNames() { return ImmutableList.of(); } } static class AstFunctionContents implements FunctionContents { private final Node n; private boolean hasNonEmptyReturns = false; private Set<String> escapedVarNames; AstFunctionContents(Node n) { this.n = n; } @Override public Node getSourceNode() { return n; } @Override public boolean mayBeFromExterns() { return n.isFromExterns(); } @Override public boolean mayHaveNonEmptyReturns() { return hasNonEmptyReturns; } void recordNonEmptyReturn() { hasNonEmptyReturns = true; } @Override public Iterable<String> getEscapedVarNames() { return escapedVarNames == null ? ImmutableList.<String>of() : escapedVarNames; } void recordEscapedVarName(String name) { if (escapedVarNames == null) { escapedVarNames = Sets.newHashSet(); } escapedVarNames.add(name); } } }

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>ClassNameIfGoog(Node node, Node parent, String functionName){ String className = null; if (NodeUtil.isExprCall(parent)) { Node callee = node.getFirstChild(); if (callee != null && callee.isGetProp()) { String qualifiedName = callee.getQualifiedName(); if (functionName.equals(qualifiedName)) { Node target = callee.getNext(); if (target != null && target.isString()) { className = target.getString(); } } } } return className; } /** * Use closure's implementation. * @return closure's function name for exporting properties. */ @Override public String getExportPropertyFunction() { return "goog.exportProperty"; } /** * Use closure's implementation. * @return closure's function name for exporting symbols. */ @Override public String getExportSymbolFunction() { return "goog.exportSymbol"; } @Override public List<String> identifyTypeDeclarationCall(Node n) { Node callName = n.getFirstChild(); if ("goog.addDependency".equals(callName.getQualifiedName()) && n.getChildCount() >= 3) { Node typeArray = callName.getNext().getNext(); if (typeArray.isArrayLit()) { List<String> typeNames = Lists.newArrayList(); for (Node name = typeArray.getFirstChild(); name != null; name = name.getNext()) { if (name.isString()) { typeNames.add(name.getString()); } } return typeNames; } } return null; } @Override public String getAbstractMethodName() { return "goog.abstractMethod"; } @Override public String getSingletonGetterClassName(Node callNode) { Node callArg = callNode.getFirstChild(); String callName = callArg.getQualifiedName(); // Use both the original name and the post-CollapseProperties name. if (!("goog.addSingletonGetter".equals(callName) || "goog$addSingletonGetter".equals(callName)) || callNode.getChildCount() != 2) { return null; } return callArg.getNext().getQualifiedName(); } @Override public void applySingletonGetter

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> Map<String, Node> provides = Maps.newHashMap(); private final Map<String, Node> ctors = Maps.newHashMap(); private final CodingConvention convention; CheckProvidesCallback(CodingConvention convention){ this.convention = convention; } @Override public void visit(NodeTraversal t, Node n, Node parent) { switch (n.getType()) { case Token.CALL: String providedClassName = codingConvention.extractClassNameIfProvide(n, parent); if (providedClassName != null) { provides.put(providedClassName, n); } break; case Token.FUNCTION: visitFunctionNode(n, parent); break; case Token.SCRIPT: visitScriptNode(t, n); } } private void visitFunctionNode(Node n, Node parent) { Node name = null; JSDocInfo info = parent.getJSDocInfo(); if (info != null && info.isConstructor()) { name = parent.getFirstChild(); } else { // look to the child, maybe it's a named function info = n.getJSDocInfo(); if (info != null && info.isConstructor()) { name = n.getFirstChild(); } } if (name != null && name.isQualifiedName()) { String qualifiedName = name.getQualifiedName(); if (!this.convention.isPrivate(qualifiedName)) { Visibility visibility = info.getVisibility(); if (!visibility.equals(JSDocInfo.Visibility.PRIVATE)) { ctors.put(qualifiedName, name); } } } } private void visitScriptNode(NodeTraversal t, Node n) { for (Map.Entry<String, Node> ctorEntry : ctors.entrySet()) { if (!provides.containsKey(ctorEntry.getKey())) { compiler.report( t.makeError(ctorEntry.getValue(), checkLevel, MISSING_PROVIDE_WARNING, ctorEntry.getKey())); } } provides.clear(); ctors.clear(); } } }

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>GraphNode<Node, Branch> candidate : cfg.getDirectedGraphNodes()) { if (!nodePriorities.containsKey(candidate)) { nodePriorities.put(candidate, ++priorityCounter); } } // Again, the implicit return node is always last. nodePriorities.put(cfg.getImplicitReturn(), ++priorityCounter); } /** * Given an entry node, find all the nodes reachable from that node * and prioritize them. */ private void prioritizeFromEntryNode(DiGraphNode<Node, Branch> entry) { PriorityQueue<DiGraphNode<Node, Branch>> worklist = new PriorityQueue<DiGraphNode<Node, Branch>>(10, priorityComparator); worklist.add(entry); while (!worklist.isEmpty()) { DiGraphNode<Node, Branch> current = worklist.remove(); if (nodePriorities.containsKey(current)) { continue; } nodePriorities.put(current, ++priorityCounter); List<DiGraphNode<Node, Branch>> successors = cfg.getDirectedSuccNodes(current); for (DiGraphNode<Node, Branch> candidate : successors) { worklist.add(candidate); } } } @Override public boolean shouldTraverse( NodeTraversal nodeTraversal, Node n, Node parent) { astPosition.put(n, astPositionCounter++); switch (n.getType()) { case Token.FUNCTION: if (shouldTraverseFunctions || n == cfg.getEntry().getValue()) { exceptionHandler.push(n); return true; } return false; case Token.TRY: exceptionHandler.push(n); return true; } /* * We are going to stop the traversal depending on what the node's parent * is. * * We are only interested in adding edges between nodes that change control * flow. The most obvious ones are loops and IF-ELSE's. A statement * transfers control to its next sibling. * * In case of an expression tree, there is no control flow within the tree * even when there are short circuited operators and conditionals. When we * are doing data flow analysis, we will simply synthesize lattices up the * expression tree by finding the meet at

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>Mode mode) { this.resolveMode = mode; } ResolveMode getResolveMode() { return resolveMode; } public ErrorReporter getErrorReporter() { return reporter; } public boolean shouldTolerateUndefinedValues() { return tolerateUndefinedValues; } /** * Reset to run the TypeCheck pass. */ public void resetForTypeCheck() { typesIndexedByProperty.clear(); eachRefTypeIndexedByProperty.clear(); initializeBuiltInTypes(); namesToTypes.clear(); namespaces.clear(); initializeRegistry(); } private void initializeBuiltInTypes() { // These locals shouldn't be all caps. BooleanType BOOLEAN_TYPE = new BooleanType(this); registerNativeType(JSTypeNative.BOOLEAN_TYPE, BOOLEAN_TYPE); NullType NULL_TYPE = new NullType(this); registerNativeType(JSTypeNative.NULL_TYPE, NULL_TYPE); NumberType NUMBER_TYPE = new NumberType(this); registerNativeType(JSTypeNative.NUMBER_TYPE, NUMBER_TYPE); StringType STRING_TYPE = new StringType(this); registerNativeType(JSTypeNative.STRING_TYPE, STRING_TYPE); UnknownType UNKNOWN_TYPE = new UnknownType(this, false); registerNativeType(JSTypeNative.UNKNOWN_TYPE, UNKNOWN_TYPE); registerNativeType( JSTypeNative.CHECKED_UNKNOWN_TYPE, new UnknownType(this, true)); VoidType VOID_TYPE = new VoidType(this); registerNativeType(JSTypeNative.VOID_TYPE, VOID_TYPE); AllType ALL_TYPE = new AllType(this); registerNativeType(JSTypeNative.ALL_TYPE, ALL_TYPE); // Top Level Prototype (the One) // The initializations of TOP_LEVEL_PROTOTYPE and OBJECT_FUNCTION_TYPE // use each other's results, so at least one of them will get null // instead of an actual type; however, this seems to be benign. PrototypeObjectType TOP_LEVEL_PROTOTYPE = new PrototypeObjectType(this, null, null, true); registerNativeType(JSTypeNative.TOP_LEVEL_PROTOTYPE, TOP_LEVEL_PROTOTYPE); // Object FunctionType OBJECT_FUNCTION_TYPE =

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>Native.NULL_TYPE)); register(getNativeType(JSTypeNative.NULL_TYPE), "Null"); register(getNativeType(JSTypeNative.NUMBER_OBJECT_TYPE)); register(getNativeType(JSTypeNative.NUMBER_TYPE)); register(getNativeType(JSTypeNative.OBJECT_TYPE)); register(getNativeType(JSTypeNative.ERROR_TYPE)); register(getNativeType(JSTypeNative.URI_ERROR_TYPE)); register(getNativeType(JSTypeNative.EVAL_ERROR_TYPE)); register(getNativeType(JSTypeNative.TYPE_ERROR_TYPE)); register(getNativeType(JSTypeNative.RANGE_ERROR_TYPE)); register(getNativeType(JSTypeNative.REFERENCE_ERROR_TYPE)); register(getNativeType(JSTypeNative.SYNTAX_ERROR_TYPE)); register(getNativeType(JSTypeNative.REGEXP_TYPE)); register(getNativeType(JSTypeNative.STRING_OBJECT_TYPE)); register(getNativeType(JSTypeNative.STRING_TYPE)); register(getNativeType(JSTypeNative.VOID_TYPE)); register(getNativeType(JSTypeNative.VOID_TYPE), "Undefined"); register(getNativeType(JSTypeNative.VOID_TYPE), "void"); register(getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE), "Function"); } private void register(JSType type) { register(type, type.toString()); } private void register(JSType type, String name) { namesToTypes.put(name, type); // Add all the namespaces in which this name lives. while (name.indexOf('.') > 0) { name = name.substring(0, name.lastIndexOf('.')); namespaces.add(name); } } private void registerNativeType(JSTypeNative typeId, JSType type) { nativeTypes[typeId.ordinal()] = type; } /** * Tells the type system that {@code owner} may have a property named * {@code propertyName}. This allows the registry to keep track of what * types a property is defined upon. * * This is NOT the same as saying that {@code owner} must have a property * named type. ObjectType#hasProperty attempts

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> must return * {@code [Object, Array]}. It would not be correct to collapse them to * {@code [Object]}. */ public Iterable<ObjectType> getEachReferenceTypeWithProperty( String propertyName) { if (eachRefTypeIndexedByProperty.containsKey(propertyName)) { return eachRefTypeIndexedByProperty.get(propertyName).values(); } else { return ImmutableList.of(); } } /** * Finds the common supertype of the two given object types. */ ObjectType findCommonSuperObject(ObjectType a, ObjectType b) { List<ObjectType> stackA = getSuperStack(a); List<ObjectType> stackB = getSuperStack(b); ObjectType result = getNativeObjectType(JSTypeNative.OBJECT_TYPE); while (!stackA.isEmpty() && !stackB.isEmpty()) { ObjectType currentA = stackA.remove(stackA.size() - 1); ObjectType currentB = stackB.remove(stackB.size() - 1); if (currentA.isEquivalentTo(currentB)) { result = currentA; } else { return result; } } return result; } private static List<ObjectType> getSuperStack(ObjectType a) { List<ObjectType> stack = Lists.newArrayListWithExpectedSize(5); for (ObjectType current = a; current != null; current = current.getImplicitPrototype()) { stack.add(current); } return stack; } /** * Increments the current generation. Clients must call this in order to * move to the next generation of type resolution, allowing types to attempt * resolution again. */ public void incrementGeneration() { for (NamedType type : resolvedNamedTypes.values()) { type.clearResolved(); } unresolvedNamedTypes.putAll(resolvedNamedTypes); resolvedNamedTypes.clear(); } boolean isLastGeneration() { return lastGeneration; } /** * Sets whether this is the last generation. In the last generation, * {@link NamedType} warns about unresolved types. */ public void setLastGeneration(boolean lastGeneration) { this.lastGeneration = lastGeneration; } /** * Tells the type system that {@code type} implements interface {@code

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> * InterfaceInstance}. * {@code inter} must be an ObjectType for the instance of the interface as it * could be a named type and not yet have the constructor. */ void registerTypeImplementingInterface( FunctionType type, ObjectType interfaceInstance) { interfaceToImplementors.put(interfaceInstance.getReferenceName(), type); } /** * Returns a collection of types that directly implement {@code * interfaceInstance}. Subtypes of implementing types are not guaranteed to * be returned. {@code interfaceInstance} must be an ObjectType for the * instance of the interface. */ public Collection<FunctionType> getDirectImplementors( ObjectType interfaceInstance) { return interfaceToImplementors.get(interfaceInstance.getReferenceName()); } /** * Records declared global type names. This makes resolution faster * and more robust in the common case. * * @param name The name of the type to be recorded. * @param t The actual type being associated with the name. * @return True if this name is not already defined, false otherwise. */ public boolean declareType(String name, JSType t) { if (namesToTypes.containsKey(name)) { return false; } register(t, name); return true; } /** * Overrides a declared global type name. Throws an exception if this * type name hasn't been declared yet. */ public void overwriteDeclaredType(String name, JSType t) { Preconditions.checkState(namesToTypes.containsKey(name)); register(t, name); } /** * Records a forward-declared type name. We will not emit errors if this * type name never resolves to anything. */ public void forwardDeclareType(String name) { forwardDeclaredTypes.add(name); } /** * Whether this is a forward-declared type name. */ public boolean isForwardDeclaredType(String name) { return forwardDeclaredTypes.contains(name); } /** Determines whether the given JS package exists. */ public boolean hasNamespace(String name) { return namespaces.contains(name); } /** * Looks up a type by name. * * @param jsTypeName The name string. * @return the corresponding JSType object or {@code null} it cannot be

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> found */ public JSType getType(String jsTypeName) { // TODO(user): Push every local type name out of namesToTypes so that // NamedType#resolve is correct. if (jsTypeName.equals(templateTypeName)) { return templateType; } return namesToTypes.get(jsTypeName); } public JSType getNativeType(JSTypeNative typeId) { return nativeTypes[typeId.ordinal()]; } public ObjectType getNativeObjectType(JSTypeNative typeId) { return (ObjectType) getNativeType(typeId); } public FunctionType getNativeFunctionType(JSTypeNative typeId) { return (FunctionType) getNativeType(typeId); } /** * Looks up a type by name. To allow for forward references to types, an * unrecognized string has to be bound to a NamedType object that will be * resolved later. * * @param scope A scope for doing type name resolution. * @param jsTypeName The name string. * @param sourceName The name of the source file where this reference appears. * @param lineno The line number of the reference. * @return a NamedType if the string argument is not one of the known types, * otherwise the corresponding JSType object. */ public JSType getType(StaticScope<JSType> scope, String jsTypeName, String sourceName, int lineno, int charno) { JSType type = getType(jsTypeName); if (type == null) { // TODO(user): Each instance should support named type creation using // interning. NamedType namedType = new NamedType(this, jsTypeName, sourceName, lineno, charno); unresolvedNamedTypes.put(scope, namedType); type = namedType; } return type; } /** * Flushes out the current resolved and unresovled Named Types from * the type registry. This is intended to be used ONLY before a * compile is run. */ public void clearNamedTypes() { resolvedNamedTypes.clear(); unresolvedNamedTypes.clear(); } /** * Resolve all the unresolved types in the given scope. */ public void resolveTypesInScope(StaticScope<JSType> scope) { for (NamedType

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> /** * Creates a named type. */ @VisibleForTesting public JSType createNamedType(String reference, String sourceName, int lineno, int charno) { return new NamedType(this, reference, sourceName, lineno, charno); } /** * Identifies the name of a typedef or enum before we actually declare it. */ public void identifyNonNullableName(String name) { Preconditions.checkNotNull(name); nonNullableTypeNames.add(name); } /** * Creates a JSType from the nodes representing a type. * @param n The node with type info. * @param sourceName The source file name. * @param scope A scope for doing type name lookups. */ public JSType createFromTypeNodes(Node n, String sourceName, StaticScope<JSType> scope) { if (resolveMode == ResolveMode.LAZY_EXPRESSIONS) { // If the type expression doesn't contain any names, just // resolve it anyway. boolean hasNames = hasTypeName(n); if (hasNames) { return new UnresolvedTypeExpression(this, n, sourceName); } } return createFromTypeNodesInternal(n, sourceName, scope); } private boolean hasTypeName(Node n) { if (n.getType() == Token.STRING) { return true; } for (Node child = n.getFirstChild(); child != null; child = child.getNext()) { if (hasTypeName(child)) { return true; } } return false; } /** @see #createFromTypeNodes(Node, String, StaticScope) */ private JSType createFromTypeNodesInternal(Node n, String sourceName, StaticScope<JSType> scope) { switch (n.getType()) { case Token.LC: // Record type. return createRecordTypeFromNodes( n.getFirstChild(), sourceName, scope); case Token.BANG: // Not nullable return createFromTypeNodesInternal( n.getFirstChild(), sourceName, scope) .restrictByNotNullOrUndefined(); case Token.QMARK: // Nullable or unknown Node firstChild = n.getFirstChild(); if (firstChild == null) { return getNativeType(UNKNOWN_TYPE

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> { return (bitset & mask) != 0x00; } // Visible for testing. public void setVisibility(Visibility visibility) { this.visibility = visibility; } private void lazyInitInfo() { if (info == null) { info = new LazilyInitializedInfo(); } } /** * Lazily initializes the documentation information object, but only * if the JSDocInfo was told to keep such information around. */ private boolean lazyInitDocumentation() { if (!includeDocumentation) { return false; } if (documentation == null) { documentation = new LazilyInitializedDocumentation(); } return true; } /** * Adds a marker to the documentation (if it exists) and * returns the marker. Returns null otherwise. */ Marker addMarker() { if (!lazyInitDocumentation()) { return null; } if (documentation.markers == null) { documentation.markers = Lists.newArrayList(); } Marker marker = new Marker(); documentation.markers.add(marker); return marker; } /** * Sets the deprecation reason. * * @param reason The deprecation reason */ boolean setDeprecationReason(String reason) { lazyInitInfo(); if (info.deprecated != null) { return false; } info.deprecated = reason; return true; } /** * Add a suppressed warning. */ public void addSuppression(String suppression) { lazyInitInfo(); if (info.suppressions == null) { info.suppressions = Sets.newHashSet(); } info.suppressions.add(suppression); } /** * Sets suppressed warnings. * @param suppressions A list of suppressed warning types. */ boolean setSuppressions(Set<String> suppressions) { lazyInitInfo(); if (info.suppressions != null) { return false; } info.suppressions = suppressions; return true; } /** * Add modifies values. */ void addModifies(String modifies) { lazyInitInfo(); if (info.modifies == null) { info.modifies = Sets.newHashSet(); } info.modifies

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>.add(modifies); } /** * Sets modifies values. * @param modifies A list of modifies types. */ boolean setModifies(Set<String> modifies) { lazyInitInfo(); if (info.modifies != null) { return false; } info.modifies = modifies; return true; } /** * Documents the version. */ boolean documentVersion(String version) { if (!lazyInitDocumentation()) { return true; } if (documentation.version != null) { return false; } documentation.version = version; return true; } /** * Documents a reference (i.e. adds a "see" reference to the list). */ boolean documentReference(String reference) { if (!lazyInitDocumentation()) { return true; } if (documentation.sees == null) { documentation.sees = Lists.newArrayList(); } documentation.sees.add(reference); return true; } /** * Documents the author (i.e. adds it to the author list). */ boolean documentAuthor(String author) { if (!lazyInitDocumentation()) { return true; } if (documentation.authors == null) { documentation.authors = Lists.newArrayList(); } documentation.authors.add(author); return true; } /** * Documents the throws (i.e. adds it to the throws list). */ boolean documentThrows(JSTypeExpression type, String throwsDescription) { if (!lazyInitDocumentation()) { return true; } if (documentation.throwsDescriptions == null) { documentation.throwsDescriptions = new LinkedHashMap<JSTypeExpression, String>(); } if (!documentation.throwsDescriptions.containsKey(type)) { documentation.throwsDescriptions.put(type, throwsDescription); return true; } return false; } /** * Documents a parameter. Parameters are described using the {@code @param} * annotation. * * @param parameter the parameter's name * @param description the parameter's description */ boolean documentParam(String parameter, String description) { if (!lazyInitDocumentation()) { return true; } if (documentation.parameters == null) {

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> name. */ boolean declareTemplateTypeName(String templateTypeName) { lazyInitInfo(); if (info.templateTypeName != null) { return false; } info.templateTypeName = templateTypeName; return true; } /** * Declares that the method throws a given type. * * @param jsType The type that can be thrown by the method. */ boolean declareThrows(JSTypeExpression jsType) { lazyInitInfo(); if (info.thrownTypes == null) { info.thrownTypes = Lists.newArrayList(); } info.thrownTypes.add(jsType); return true; } /** * Gets the visibility specified by {@code @private}, {@code @protected} or * {@code @public} annotation. If no visibility is specified, visibility * is inherited from the base class. */ public Visibility getVisibility() { return visibility; } /** * Gets the parameter type. * @param parameter the parameter's name * @return the parameter's type or {@code null} if this parameter is not * defined or has a {@code null} type */ public JSTypeExpression getParameterType(String parameter) { if (info == null || info.parameters == null) { return null; } return info.parameters.get(parameter); } /** * Returns whether the parameter is defined. */ public boolean hasParameter(String parameter) { if (info == null || info.parameters == null) { return false; } return info.parameters.containsKey(parameter); } /** * Returns whether the parameter has an attached type. * * @return {@code true} if the parameter has an attached type, {@code false} * if the parameter has no attached type or does not exist. */ public boolean hasParameterType(String parameter) { return getParameterType(parameter) != null; } /** * Returns the set of names of the defined parameters. The iteration order * of the returned set is not the order in which parameters are defined. * * @return the set of names of the defined parameters. The returned set is * immutable. */ public Set<String> getParameterNames() { if (info == null || info.

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> * Adds an implemented interface. Returns whether the interface was added. If * the interface was already present in the list, it won't get added again. */ boolean addImplementedInterface(JSTypeExpression interfaceName) { lazyInitInfo(); if (info.implementedInterfaces == null) { info.implementedInterfaces = Lists.newArrayListWithCapacity(2); } if (info.implementedInterfaces.contains(interfaceName)) { return false; } info.implementedInterfaces.add(interfaceName); return true; } /** * Returns the types specified by the {@code @implements} annotation. * * @return An immutable list of JSTypeExpression objects that can * be resolved to types. */ public List<JSTypeExpression> getImplementedInterfaces() { if (info == null || info.implementedInterfaces == null) { return ImmutableList.of(); } return Collections.unmodifiableList(info.implementedInterfaces); } /** * Gets the number of interfaces specified by the {@code @implements} * annotation. */ public int getImplementedInterfaceCount() { if (info == null || info.implementedInterfaces == null) { return 0; } return info.implementedInterfaces.size(); } /** * Adds an extended interface (for interface only). * Returns whether the type was added. * if the type was already present in the list, it won't get added again. */ boolean addExtendedInterface(JSTypeExpression type) { lazyInitInfo(); if (info.extendedInterfaces == null) { info.extendedInterfaces = Lists.newArrayListWithCapacity(2); } if (info.extendedInterfaces.contains(type)) { return false; } info.extendedInterfaces.add(type); return true; } /** * Returns the interfaces extended by an interface * * @return An immutable list of JSTypeExpression objects that can * be resolved to types. */ public List<JSTypeExpression> getExtendedInterfaces() { if (info == null || info.extendedInterfaces == null) { return ImmutableList.of(); } return Collections.unmodifiableList(info.extendedInterfaces); } /** * Gets the number of extended interfaces specified */ public int getExtendedInterfacesCount() { if (info

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>Description() { return documentation == null ? null : documentation.blockDescription; } /** * Returns whether this has a fileoverview flag. */ public boolean hasFileOverview() { return getFlag(MASK_FILEOVERVIEW); } /** * Returns the file overview or null if none specified. */ public String getFileOverview() { return documentation == null ? null : documentation.fileOverview; } public Node getAssociatedNode() { return this.associatedNode; } /** * Sets the node associated with this JSDoc. * Notice that many nodes may have pointer to the same JSDocInfo * object (because we propagate it across the type graph). But there * is only one canonical "owner" node of the JSDocInfo, which corresponds * to its original place in the syntax tree. */ public void setAssociatedNode(Node node) { this.associatedNode = node; } /** Gets the name of the source file that contains this JSDoc. */ public String getSourceName() { return this.associatedNode != null ? this.associatedNode.getSourceFileName() : null; } /** Gets the list of all markers for the documentation in this JSDoc. */ public Collection<Marker> getMarkers() { return (documentation == null || documentation.markers == null) ? ImmutableList.<Marker>of() : documentation.markers; } /** Gets the template type name. */ public String getTemplateTypeName() { if (info == null) { return null; } return info.templateTypeName; } /** * Returns a collection of all type nodes that are a part of this JSDocInfo. * This includes @type, @this, @extends, @implements, @param, @throws, * and @return. Any future type specific JSDoc should make sure to add the * appropriate nodes here. * @return collection of all type nodes */ public Collection<Node> getTypeNodes() { List<Node> nodes = Lists.newArrayList(); if (type != null) { nodes.add(type.getRoot()); } if (thisType != null) { nodes.add(thisType.getRoot()); } if (info != null) { if (info.baseType !=

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> null) { nodes.add(info.baseType.getRoot()); } if (info.extendedInterfaces != null) { for (JSTypeExpression interfaceType : info.extendedInterfaces) { nodes.add(interfaceType.getRoot()); } } if (info.implementedInterfaces != null) { for (JSTypeExpression interfaceType : info.implementedInterfaces) { nodes.add(interfaceType.getRoot()); } } if (info.parameters != null) { for (JSTypeExpression parameterType : info.parameters.values()) { if (parameterType != null) { nodes.add(parameterType.getRoot()); } } } if (info.thrownTypes != null) { for (JSTypeExpression thrownType : info.thrownTypes) { if (thrownType != null) { nodes.add(thrownType.getRoot()); } } } } return nodes; } public boolean hasModifies() { return info != null && info.modifies != null; } /** * Returns the original JSDoc comment string. Returns null unless * parseJsDocDocumentation is enabled via the ParserConfig. */ public String getOriginalCommentString() { return documentation == null ? null : documentation.sourceComment; } void setOriginalCommentString(String sourceComment) { if (!lazyInitDocumentation()) { return; } documentation.sourceComment = sourceComment; } }

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>Pass()) { loopStart = passName; } else if (loopStart != null && pass.isOneTimePass()) { graph.connect(lastPass, "loop", loopStart); loopStart = null; } if (lastPass != null) { graph.connect(lastPass, "", passName); } lastPass = passName; } return graph; } /** * Create a type inference pass. */ final TypeInferencePass makeTypeInference(AbstractCompiler compiler) { return new TypeInferencePass( compiler, compiler.getReverseAbstractInterpreter(), topScope, typedScopeCreator); } final InferJSDocInfo makeInferJsDocInfo(AbstractCompiler compiler) { return new InferJSDocInfo(compiler); } /** * Create a type-checking pass. */ final TypeCheck makeTypeCheck(AbstractCompiler compiler) { return new TypeCheck( compiler, compiler.getReverseAbstractInterpreter(), compiler.getTypeRegistry(), topScope, typedScopeCreator, options.reportMissingOverride, options.reportUnknownTypes) .reportMissingProperties(options.enables( DiagnosticGroup.forType(TypeCheck.INEXISTENT_PROPERTY))); } /** * Insert the given pass factory before the factory of the given name. */ final static void addPassFactoryBefore( List<PassFactory> factoryList, PassFactory factory, String passName) { factoryList.add( findPassIndexByName(factoryList, passName), factory); } /** * Find a pass factory with the same name as the given one, and replace it. */ final static void replacePassFactory( List<PassFactory> factoryList, PassFactory factory) { factoryList.set( findPassIndexByName(factoryList, factory.getName()), factory); } /** * Throws an exception if no pass with the given name exists. */ private static int findPassIndexByName( List<PassFactory> factoryList, String name) { for (int i = 0; i < factoryList.size(); i++) { if (factoryList.get(i).getName().equals(name)) { return i; } } throw new IllegalArgumentException( "No factory named '" + name +

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> compilation job. * * This does not affect how we handle files that do not provide symbols. * See setMoocherDropping for information on how these are handled. */ public void setDependencyPruning(boolean enabled) { this.pruneDependencies = enabled; } /** * Enables or disables moocher dropping mode. * * A 'moocher' is a file that does not provide any symbols (though they * may require symbols). This is usually because they don't want to * tie themselves to a particular dependency system (e.g., Closure's * goog.provide, CommonJS modules). So they rely on other people to * manage dependencies on them. * * If true, we drop these files when we prune dependencies. * If false, we always keep these files an anything they depend on. * The default is false. * * Notice that this option only makes sense if dependency pruning is on, * and a set of entry points is specified. */ public void setMoocherDropping(boolean enabled) { this.dropMoochers = enabled; } /** * Adds a collection of symbols to always keep. * * In dependency pruning mode, we will automatically keep all the * transitive dependencies of these symbols. * * The syntactic form of a symbol depends on the type of dependency * primitives we're using. For example, goog.provide('foo.bar') * provides the symbol 'foo.bar'. */ public void setEntryPoints(Collection<String> symbols) { entryPoints.clear(); entryPoints.addAll(symbols); } /** Returns whether re-ordering of files is needed. */ boolean needsManagement() { return sortDependencies || pruneDependencies; } boolean shouldSortDependencies() { return sortDependencies; } boolean shouldPruneDependencies() { return pruneDependencies; } boolean shouldDropMoochers() { return pruneDependencies && dropMoochers; } Collection<String> getEntryPoints() { return entryPoints; } }

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> Iterable<ObjectType> getAllImplementedInterfaces() { // Store them in a linked hash set, so that the compile job is // deterministic. Set<ObjectType> interfaces = Sets.newLinkedHashSet(); for (ObjectType type : getImplementedInterfaces()) { addRelatedInterfaces(type, interfaces); } return interfaces; } private void addRelatedInterfaces(ObjectType instance, Set<ObjectType> set) { FunctionType constructor = instance.getConstructor(); if (constructor != null) { if (!constructor.isInterface()) { return; } set.add(instance); for (ObjectType interfaceType : instance.getCtorExtendedInterfaces()) { addRelatedInterfaces(interfaceType, set); } } } /** Returns interfaces implemented directly by a class or its superclass. */ public Iterable<ObjectType> getImplementedInterfaces() { FunctionType superCtor = isConstructor() ? getSuperClassConstructor() : null; if (superCtor == null) { return implementedInterfaces; } else { return Iterables.concat( implementedInterfaces, superCtor.getImplementedInterfaces()); } } /** Returns interfaces directly implemented by the class. */ public Iterable<ObjectType> getOwnImplementedInterfaces() { return implementedInterfaces; } public void setImplementedInterfaces(List<ObjectType> implementedInterfaces) { // Records this type for each implemented interface. for (ObjectType type : implementedInterfaces) { registry.registerTypeImplementingInterface(this, type); } this.implementedInterfaces = ImmutableList.copyOf(implementedInterfaces); } /** * Returns all extended interfaces declared by an interfaces or its super- * interfaces. If this is called before all types are resolved, it may return * an incomplete set. */ public Iterable<ObjectType> getAllExtendedInterfaces() { // Store them in a linked hash set, so that the compile job is // deterministic. Set<ObjectType> extendedInterfaces = Sets.newLinkedHashSet(); for (ObjectType interfaceType : getExtendedInterfaces()) { addRelatedExtendedInterfaces(interfaceType, extendedInterfaces); } return extendedInterfaces; } private void addRelatedExtendedInterfaces(ObjectType instance, Set<ObjectType> set) { FunctionType constructor = instance.getConstructor(); if (constructor != null) { set.add(instance); for (ObjectType interfaceType : constructor.get

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS> } /** * Sets the instance type. This should only be used for special * native types. */ void setInstanceType(ObjectType instanceType) { typeOfThis = instanceType; } /** * Returns whether this function type has an instance type. */ public boolean hasInstanceType() { return isConstructor() || isInterface(); } /** * Gets the type of {@code this} in this function. */ @Override public ObjectType getTypeOfThis() { return typeOfThis.isNoObjectType() ? registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE) : typeOfThis; } /** * Gets the source node or null if this is an unknown function. */ public Node getSource() { return source; } /** * Sets the source node. */ public void setSource(Node source) { if (prototypeSlot != null) { // NOTE(bashir): On one hand when source is null we want to drop any // references to old nodes retained in prototypeSlot. On the other hand // we cannot simply drop prototypeSlot, so we retain all information // except the propertyNode for which we use an approximation! These // details mostly matter in hot-swap passes. if (source == null || prototypeSlot.getNode() == null) { prototypeSlot = new Property(prototypeSlot.getName(), prototypeSlot.getType(), prototypeSlot.isTypeInferred(), source); } } this.source = source; } /** Adds a type to the list of subtypes for this type. */ private void addSubType(FunctionType subType) { if (subTypes == null) { subTypes = Lists.newArrayList(); } subTypes.add(subType); } @Override public void clearCachedValues() { super.clearCachedValues(); if (subTypes != null) { for (FunctionType subType : subTypes) { subType.clearCachedValues(); } } if (!isNativeObjectType()) { if (hasInstanceType()) { getInstanceType().clearCachedValues(); } if (prototypeSlot != null) { ((PrototypeObjectType) prototypeSlot.getType()).clearCachedValues(); } } } /** * Returns a list of types that are subtypes of this type

Closure, 43

<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB> */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Object literals with a @lends annotation aren't analyzed until we * reach the root of the statement they're defined in. * * This ensures that if there are any @lends annotations on the object * literals, the type on the @lends annotation resolves correctly. * * For more information, see * http://code.google.com/p/closure-compiler/issues/detail?id=314 */ <CHANGES> <CHANGEE> /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; firstChild, n, firstChild.getNext()); } break; case Token.CATCH: defineCatch(n, parent); break; case Token.VAR: defineVar(n, parent); break; case Token.GETPROP: // Handle stubbed properties. if (parent.isExprResult() && n.isQualifiedName()) { maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null); } break; } // Analyze any @lends object literals in this statement. <CHANGES> <CHANGEE> } private void attachLiteralTypes(NodeTraversal t, Node n) { switch (n.getType()) { case Token.NULL: n.setJSType(getNativeType(NULL_TYPE)); break; case Token.VOID: n.setJSType(getNativeType(VOID_TYPE)); break; case Token.STRING: // Defer keys to the Token.OBJECTLIT case if (!NodeUtil.isObjectLitKey(n, n.getParent())) { n.setJSType(getNativeType(STRING_TYPE)); } break; case Token.NUMBER: n.set<SCANS>. This is only valid * for constructor functions, and may be null. This allows a downward * traversal of the subtype graph. */ public List<FunctionType> getSubTypes() { return subTypes; } @Override public boolean hasCachedValues() { return prototypeSlot != null || super.hasCachedValues(); } /** * Gets the template type name. */ public String getTemplateTypeName() { return templateTypeName; } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { setResolvedTypeInternal(this); call = (ArrowType) safeResolve(call, t, scope); if (prototypeSlot != null) { prototypeSlot.setType( safeResolve(prototypeSlot.getType(), t, scope)); } // Warning about typeOfThis if it doesn't resolve to an ObjectType // is handled further upstream. // // TODO(nicksantos): Handle this correctly if we have a UnionType. // // TODO(nicksantos): In ES3, the runtime coerces "null" to the global // activation object. In ES5, it leaves it as null. Just punt on this // issue for now by coercing out null. This is complicated by the // fact that when most people write @this {Foo}, they really don't // mean "nullable Foo". For certain tags (like @extends) we de-nullify // the name for them. JSType maybeTypeOfThis = safeResolve(typeOfThis, t, scope); if (maybeTypeOfThis != null) { maybeTypeOfThis = maybeTypeOfThis.restrictByNotNullOrUndefined(); } if (maybeTypeOfThis instanceof ObjectType) { typeOfThis = (ObjectType) maybeTypeOfThis; } boolean changed = false; ImmutableList.Builder<ObjectType> resolvedInterfaces = ImmutableList.builder(); for (ObjectType iface : implementedInterfaces) { ObjectType resolvedIface = (ObjectType) iface.resolve(t, scope); resolvedInterfaces.add(resolvedIface); changed |= (resolvedIface != iface); } if (changed) { implementedInterfaces = resolvedInterfaces.build(); } if (subTypes != null) { for (int i = 0; i < subTypes.size(); i++)